问答

汇集网友智慧,解决技术难题

21ic问答首页 - f460是不是没有FSMC,我手册看了好久,都没找到

hc32f460 FSMC fm ST STM

f460是不是没有FSMC,我手册看了好久,都没找到

26958773522022-01-18
是不是没有类似于stm32的fsmc或者叫FMC这类的总线搜索
复制

回答 +关注 2
4341人浏览 7人回答问题 分享 举报
7 个回答
  • st32的要100脚以上的才有
  • 小华HC32F4系列分为F460和F4A0, 带总线接口的是F4A0系列,总线接口叫EXMC
  • https://www.cnblogs.com/schips/p/10999836.html


    【转】STM32的FSMC详解
    STM32的FSMC真是一个万能的总线控制器,不仅可以控制SRAM,NOR FLASH,NAND FLASH,PC Card,还能控制LCD,TFT.
    一般越是复杂的东西,理解起来就很困难,但是使用上却很方便,如USB。
    不过FSMC也有很诡异的地方.如
    *([color=rgb(86, 156, 214) !important]volatile uint16_t *)0x60400000=0x0;


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

    为什么呢?那时我还以为软件或硬件还是芯片有BUG,
    我就是从上面的不解中开始研究FSMC的…..
    1.FSMC信号引脚
    STM32的管脚排列很没有规律,而且分布在多个不同端口上,初始化要十分小心.需要用到的引脚都要先初始化成”复用功能推挽输出”模式.(GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP )
    并且开启时钟 (RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE); ) 像STM32F103Z(144脚)芯片有独立的地址和数据总线,而STM32F103V(100脚)就没有, 地址和数据总线要像51单片机一样分时复用,而在STM32F103R系列(64脚)就没有FSMC模块.
    复用总线时管脚:
    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
    独立的地址总线管脚:
    [注:总线是16Bit情况下,FSMC通过FSMC_NBL1,FSMC_NBL0,区分高低字节.下面W代表WORD,即16BIT字.]
    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
    独立的数据总线管脚:
    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
    控制信号
    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.地址的分配
    地址与片选是挂勾的,也就是说器件挂载在哪个片选引脚上,就固定了访问地址范围和FsmcInitStructure.FSMC_Bank
    • [color=rgb(87, 166, 74) !important]//地址范围:0x60000000~0x63FFFFFF,片选引脚PD7(FSMC_NE1),最大支持容量64MB,

    • [color=rgb(87, 166, 74) !important]//[在STM32F103V(100脚)上地址范围为A0~A23,最大容量16MB]

    • FsmcInitStructure.FSMC_Bank =FSMC_Bank1_NORSRAM1;


    • [color=rgb(87, 166, 74) !important]//地址范围:0x64000000~0x67FFFFFF, 片选引脚PG9(FSMC_NE2),最大支持容量64MB

    • FsmcInitStructure.FSMC_Bank =FSMC_Bank1_NORSRAM2;


    • [color=rgb(87, 166, 74) !important]//地址范围:0x68000000~0x6BFFFFFF,片选引脚PG10(FSMC_NE3),最大支持容量64MB

    • FsmcInitStructure.FSMC_Bank =FSMC_Bank1_NORSRAM3;


    • [color=rgb(87, 166, 74) !important]//地址范围:0x6C000000~0x6FFFFFFF,片选引脚(PG12 FSMC_NE4),最大支持容量64MB

    • FsmcInitStructure.FSMC_Bank =FSMC_Bank1_NORSRAM4;



    3.时序测量
    简单原理草图
    20160609191951431.jpg
    写数据的时序
    20160609192113237.jpg
    20160609214417879.jpg
    读数据的时序
    20160609214408670.jpg
    1.数据总线设定为16位宽情况下测量FSMC时序,即
    [color=rgb(156, 220, 254) !important]FsmcInitStructure.FSMC_MemoryDataWidth =    FSMC_MemoryDataWidth_16b;   
    使用逻辑分析仪测量(循环执行下面这条语句,下同)的波形
    *([color=rgb(86, 156, 214) !important]volatile uint16_t *)(0x60002468UL)=0xABCD;           
    20160609192546137.jpg
    可以看出NADV下降沿瞬间DATABUS上的数据被锁存器锁存,接着NWE低电平,总线输出0xABCD,数据0xABCD被写入0x1234这个地址.
          *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60002469UL )=0xABCD;              
    20160609193146467.jpg
    what?向这个地址写出现了两次总线操作.
    为了一探究竟,我引出了控制线.
    *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000468UL  )=0xABCD;           
    向0x60000468UL写入0xABCD到底会发什么?
    20160609193850657.jpg
    从时序图中我们可以看到, 向0x60000468UL在地址(在范围:0x60000000~0x63FFFFFF内)写入数据,片选引脚PD7(FSMC_NE1)被拉低.而在这之前,数据总线上先产生0x234,于是在NADV下降沿瞬间,数据被锁存在地址锁存器上(A0~A15),与A16~A25(如果有配置的话,会在NE1下降沿同时送出)组合成完整的地址信号.然而有人会问这个0x234是哪来的,你是否注意到它正好等于0x468/2,难道是巧合吗?不是的,在16位数据总线情况下(NORSRAMInitStrc.FSMC_MemoryDataWidth=FSMC_MemoryDataWidth_16b;),
    像这样
    *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000000|addr)=0xABCD;   
    写入一个值,实际在地址线上产生的值是addr/2(即addr>>2),
    所以如果我们一定要向addrx写入0xABCD则我们要这样写
    [color=rgb(156, 220, 254) !important]*(volatile uint16_t*)(0x60000000|addrx<<1)=0xABCD;
    NADV为高电平时, NEW被拉低,NOE为高,且NBL1,NBL0为低,随后数据总线线上产生0xABCD于是0xABCD被写进SRAM的地址0x234中
    那如果我们向一个奇数地址像这样
    *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000469UL  )=0xABCD;写入值会发生什么呢?
    20160609194439817.jpg
    从图中我们可以看到,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.
    当我们查看反汇编时发现,指令是相同的
    • [color=rgb(184, 215, 163) !important]0x080036C4 0468 DCW 0x0468

    • [color=rgb(184, 215, 163) !important]0x080036C6 6000 DCW 0x6000

    • [color=rgb(86, 156, 214) !important]MOVW r0,#0xABCD

    • [color=rgb(215, 186, 125) !important]LDR r1,[pc,#420] ; @0x080036C4//r1=0x60000468

    • STRH [color=rgb(78, 201, 176) !important]r0,[r1,#0x00]



    • [color=rgb(184, 215, 163) !important]0x080036C4 0469 DCW 0x0469

    • [color=rgb(184, 215, 163) !important]0x080036C6 6000 DCW 0x6000

    • [color=rgb(86, 156, 214) !important]MOVW r0,#0xABCD

    • LDR [color=rgb(78, 201, 176) !important]r1,[pc,#420] ; @0x080036C4//r1=0x60000469

    • STRH [color=rgb(78, 201, 176) !important]r0,[r1,#0x00]



    以上是写入的时序,下面测量读取的时序
    首先我们向SRAM的真实地址0x234,0x235分别写入0x8824,0x6507
    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000000UL |0x234 <<1 )=0x8824;

    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000000UL |0x235 <<1 )=0x6507;

    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000000UL |0x236 <<1 )=0x6735;

    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000000UL |0x237 <<1 )=0x2003;

    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000000UL |0x238 <<1 )=0x6219;


    然后读取:
    tmp=*([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000468UL  );
    20160609195831290.jpg
    如图tmp结果为0x8824
    再试
      tmp=*([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000469UL  );
    • 1
    • 2
    20160609195948289.jpg
    nUB=nLB=0;按16bit读
    从0x234读得0X8824取高字节”88”作tmp低8位
    从0x235读得0X6507取低字节”07”作tmp高8位
    最终tmp=0x0788
    接下来验证更特殊的
    *([color=rgb(86, 156, 214) !important]volatile uint8_t*)(0x60000469UL   )=0xABCD;
    20160609200824684.jpg
    由于NBL1=0,NBL0=1,0xCD被写入0x234的高地址,
    数据总线上出现的值是0xCDNN, NN是随机数据,不过一般是和高位一样的值
    *([color=rgb(86, 156, 214) !important]volatile uint8_t*)(0x60000468UL   )=0xABCD;
    20160609201041429.jpg
    由于NBL1=1,NBL0=0,0xCD被写入0x234的低地址,
    数据总线上出现的值是0xNNCD,NN是随机数据
    验证字节读取的
    首先我们向SRAM的真实地址0x234,0x235分别写入0x8824,0x6507
    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000000UL |0x234 <<1 )=0x8824;

    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000000UL |0x235 <<1 )=0x6507;


    然后这样读取
    tmp=*([color=rgb(86, 156, 214) !important]volatile uint8_t*)(0x60000469UL   );//对奇地址的单字节读取,数据总线的高8位被返回 tmp=0x88
    20160609201424046.jpg
    tmp=*([color=rgb(86, 156, 214) !important]volatile uint8_t*)(0x60000468UL   );//对偶地址的单字节读取,数据总线的低8位被返回 tmp=0x24
    20160609201438452.jpg
    还有更特殊的没有,有!
    *([color=rgb(86, 156, 214) !important]volatile int64_t*)(0x60000468UL)=0XABCDEF1234567890;//0XABCD EF12 3456 7890,如图,分别进行了4次操作才写完:
    20160609202107924.jpg
    *([color=rgb(86, 156, 214) !important]volatile int64_t*)(0x60000469UL)=0XABCDEF1234567890;//0XABCD EF12 3456 7890,如图,对奇地址写比偶地址多一次操作:
    20160609202442417.jpg
    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000000UL |0x234 <<1 )=0x8824;

    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000000UL |0x235 <<1 )=0x6507;

    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000000UL |0x236 <<1 )=0x6735;

    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000000UL |0x237 <<1 )=0x2003;

    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000000UL |0x238 <<1 )=0x6219;


    tmp=*([color=rgb(86, 156, 214) !important]volatile int64_t*)(0x60000469UL);// tmp=0x1920036735650788
    20160609202634068.jpg
    tmp=*([color=rgb(86, 156, 214) !important]volatile int64_t*)(0x60000468UL); //tmp=0x2003673565078824
    20160609202648724.jpg
    1.数据总线设定为8位宽情况下测量FSMC时序,即
    FsmcInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b;
    *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000468UL  )=0xABCD;
    20160609203153239.jpg
    *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000469UL  )=0xABCD;
    20160609203206367.jpg
    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000468UL )=0x3344;

    • *([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000469UL )=0xABCD;



    tmp=(volatile uint16_t)(0x60000469UL ); //tmp=0xabcd
    20160609203502586.jpg
    tmp=*([color=rgb(86, 156, 214) !important]volatile uint16_t*)(0x60000468UL  );
    tmp=0xcd44 20160609203618791.jpg
    tmp=*([color=rgb(86, 156, 214) !important]volatile uint8_t*)(0x60000468UL  );
    tmp=0x44
    20160609204947996.jpg
    • tmp=*([color=rgb(86, 156, 214) !important]volatile uint8_t*)(0x60000469UL );

    • tmp=[color=rgb(184, 215, 163) !important]0xcd



    20160609204955231.jpg
    *([color=rgb(86, 156, 214) !important]volatile uint8_t*)(0x60000469UL   )=0xABCD;
    20160609205003858.jpg
    *([color=rgb(86, 156, 214) !important]volatile uint8_t*)(0x60000468UL   )=0xABCD;
    20160609205018874.jpg
    • tmp=*([color=rgb(86, 156, 214) !important]volatile uint64_t*)(0x60000468UL );

    • tmp=[color=rgb(184, 215, 163) !important]0x2003673565ABCD44 20160609205401002.jpg



    tmp=*([color=rgb(86, 156, 214) !important]volatile uint64_t*)(0x60000469UL  );//tmp=0x192003673565ABCD
    20160609205448159.jpg
    *([color=rgb(86, 156, 214) !important]volatile uint64_t*)(0x60000469UL  )=0XABCDEF1234567890;  
    20160609205541626.jpg
    *([color=rgb(86, 156, 214) !important]volatile uint64_t*)(0x60000468UL  )=0XABCDEF1234567890;  
    20160609205552032.jpg



    [color=var(--color-text-secondary)]如果说我的**对你有用,只不过是我站在巨人的肩膀上再继续努力罢了。
    若在页首无特别声明,本篇**由 Schips 经过整理后发布。
    博客地址:https://www.cnblogs.com/schips/






  • 应该是没这个功能
  • HC32F460,各个封装,都没有
  • 是不是和f103zet6和rct6一样,虽然一个系列脚少的没有fsmc
  • F460指的是谁家的芯片呢?华大的HC32F460吗?搜索FSMC即可,没有就是没有

您需要登录后才可以回复 登录 | 注册