关闭

fsmc

753人阅读 评论(0) 收藏 举报
分类:


16位宽度存储器的外部地址FSMC_A[24:0]貌似每个地址代表16位宽度。stm32的内部都是以字节形式存在的。所以地址要右移一位



1、如果我的FSMC的A0与某外设的A1相连,而外设的A0与FSMC的NBL0相连,这样地址需要偏移吗?
如果是16位模式 要的 地址偏移是FSMC内部的固化操作 如果你选择16位模式就会有地址偏移(稍后说明原因) 这样做是为了用户使用方便
2、另外如果设置数据宽度为16bit,那么NBL0和NBL1不应该都是输出高吗? 
不一定 偶字节读写时仅NBL0有效,奇字节读写时仅NBL1有效 字读写都有效(低电平有效)
3、有点乱。因为是确实看见有人讲外设的A0与FSMC的NBL0相连 
不知道 没见过

这里说一下我对FSMC地址操作的一点认识

首先说一个前提:STM32 单片机的一个地址(如:0x20000000)是一个字节 
也就是说如果定义一个16位数组 u16 temp[5]  如果temp对应的地址是0x00000000 那么temp+1对应的地址是0x00000002 (地址是加2)

假设此时我们有一个 64K*8bit 的sram
那很简单 stm32的A0~A15 与存储器A0~A15连接 大家很容易理解

若此时是 64K*16bit 的sram
也就是此时sram的一个地址对应两个字节 但是stm32是一个地址一个字节 这就出现了对准的问题
如果我们的地址线依然是stm32A0~A15 和 存储器的A0~A15 连接 
如果stm32要从sram中读取前面提到数组中的temp[1]
stm32会给出0x0002(二进制地址0000000000000010b) 可是对于我们这个sram来说 读到却是temp[2],因为sram一个地址就是一个16位数据 
为了解决这个问题 我们只需要在给sram送地址时 右移一位 再送地址 即可(sram的一个地址对应stm32两个地址的数据)
比如读取0x0002 右移一位(即除2)为0x0001(0000000000000010b) 此时对应的就是temp[1]
而为了给用户提供方便 如果你选择的是16位宽度的sram FSMC会在你送地址的时候自动为你做右移一位的操作 
此时会有另外一个问题 每次都右移一位 A0没用吗 也即只能读写偶地址的数据吗?
这也就是NBL0和NBL1的作用了 如果你要进行字节操作 
如stm32发送地址0x0001读取一个字节 右移一位对应的是sram地址0x0000处的16位数据 FSMC会根据AO 来控制NBLO和NBL110 读取高字节数据
所以呢  偶字节读写时仅NBL0有效,奇字节读写时仅NBL1有效 字读写都有效(低电平有效)

//----------------------------------------------------------------------------------------


对地址65535写8位的数i代码
      *(vu8*)(Bank1_SRAM3_ADDR+65534)=i;
      i++;
   
STM32通过FSMC写8位数据
C代码中地址为实际要写入的地址字节,若将FSMC 的数据位宽配置为16位,则每次寻址实际都寻址了两个字节,例如,FSMC的地址总线值为0,则实际位于地址0有16位,两个字节,因此需要通过高低字节控制信号来区分,即LB和UB信号(注意:所有控制信号都是低电平有效)。例如当希望对地址0上的高字节进行寻址时,则FSMC总线地址值任然为0,同时LB无效(高电平)UB有效(低电平),即可实现对地址0上的高字节单独寻址。假设C代码中的要写入的地址为C_Addr,则实际FSMC总线上地址线的值与LB、UB值的状态为:
FSMC_ADDR = C_Addr/2
FSMC_LB = C_Addr%2
FSMC_UB =~ (C_Addr%2)
16位操作方式:
对地址65534写16位的数6555代码
      *(vu16*)(Bank1_SRAM3_ADDR+65534)=6555;
   
STM32通过FSMC写16位数据
C代码中地址为实际要写入的地址字节,若将FSMC 的数据位宽配置为16位,则每次寻址实际都寻址了两个字节,例如,FSMC的地址总线值为0,则实际位于地址0有16位,两个字节,因此需要通过高低字节控制信号来区分,即LB和UB信号(注意:所有控制信号都是低电平有效)。例如当希望对地址0上的高字节进行寻址时,则FSMC总线地址值任然为0,同时LB无效(高电平)UB有效(低电平),即可实现对地址0上的高字节单独寻址。假设C代码中的要写入的地址为C_Addr,则实际FSMC总线上地址线的值与LB、UB值的状态为:
如果C_Addr为偶数,则
FSMC_ADDR = C_Addr/2
FSMC_LB = FSMC_UB = 0;
FSMC一次性即可完成16位数据的写入。
如果C_Addr为奇数,则实际FSMC会将数据分成两个8位的数据来进行操作,因此效率会低很多。
先写C_Addr,写入数据字节为待写入数据的高字节
FSMC_ADDR = C_Addr/2
FSMC_LB =1;
FSMC_UB =0;
然后写C_Addr + 1地址,写入数据字节为待写入数据的低字节
FSMC_ADDR = (C_Addr + 1) /2
FSMC_LB =0;
FSMC_UB =1;
32位操作方式:
对地址65534写32位的数1265536(0x134F80)代码
      *(vu32*)(Bank1_SRAM3_ADDR+65534)= 1265536;
   
STM32通过FSMC写32数据
C代码中地址为实际要写入的地址字节,若将FSMC 的数据位宽配置为16位,则每次寻址实际都寻址了两个字节,例如,FSMC的地址总线值为0,则实际位于地址0有16位,两个字节,因此需要通过高低字节控制信号来区分,即LB和UB信号(注意:所有控制信号都是低电平有效)。例如当希望对地址0上的高字节进行寻址时,则FSMC总线地址值任然为0,同时LB无效(高电平)UB有效(低电平),即可实现对地址0上的高字节单独寻址。假设C代码中的要写入的起始地址为C_Addr,则实际FSMC总线上地址线的值与LB、UB值的状态为:
如果C_Addr为4的倍数,则FSMC首先在起始地址处写入待写入数据的低字节和次低字节:
FSMC_ADDR = C_Addr/2
FSMC_LB = FSMC_UB = 0;
然后FSMC再在起始地址+2处写入待写入数据的低字节和次低字节:
FSMC_ADDR = (C_Addr+2)/2
FSMC_LB = FSMC_UB = 0;
只需要两次16位数据写入操作即可完成一个32位数据的写入,因此效率较高。
如果C_Addr为奇数,则实际FSMC会将数据分成两个8位的数据和一个16位的数据来进行操作,需要3次写入操作才能完成32位数据的写入(效率较低)。
FSMC首先在起始地址(C_Addr)位置以8位写入方式写入待写入数据的低字节:
FSMC_ADDR = C_Addr/2
FSMC_LB = 1;
FSMC_UB = 0;
然后FSMC再在起始地址+2处(C_Addr + 2)以16位数据方式写入带写入数据的次低字节和次高字节:
FSMC_ADDR = (C_Addr+2)/2
FSMC_LB = FSMC_UB = 0;
最后FSMC再在起始地址+4处(C_Addr + 2)以8位写入方式写入待写入数据的高字节:
FSMC_ADDR = (C_Addr+4)/2
FSMC_LB = 0;
FSMC_UB = 1;

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:981808次
    • 积分:11744
    • 等级:
    • 排名:第1281名
    • 原创:81篇
    • 转载:998篇
    • 译文:3篇
    • 评论:48条
    最新评论