“ 对于16位宽度的外部存储器,FSMC将在内部使用HADDR[25:1]产生外部存储器的地址FSMC_A[24:0]”
相当与使用16位模式时,地址会自动交错一位
如何屏蔽此功能(不交错, 0对0 1对1 2对2)
不可以。
如果屏蔽此功能,地址最低位将始终是"0",这样做有什么意义?
我的意思是在地址数据复用模式下, 我用16位宽度访问的时候就有问题了。
如下图:
STM32内部 STM32外部 连接的ASIC
HADDR[ 1] --- AD[ 0] ------AD[0]
HADDR[ 2] --- AD[ 1] ------AD[1]
-
-
HADDR[16] --- AD[15] ---- AD[15]
像上面的连接,是为了保证数据D0~D15的对齐关系。
但是STM32内部的真实数据地址却是错位的,这样我要访问0x*000 0002的地址数据,那么就必须使用
地址0x*000 0004的地址,因为STM32内部自动右移动一位。如果STM32不可以禁止这个功能的话,那
么对于这种16位宽数据访问的,地址数据复用模式的情况下,就有一半的地址出现不了了。
更严重的问题是:
如果我访问的数据室32位时,就出现无法访问的问题了。只能分2次进行读写。
所以请问,STM32如何处理这种问题呢?
是真实的实测。现在就出现问题了。
如果原来是按照16BIT读,我可以自动把2000的地址编程4000进行读。
但是如果想连续的读32bit的数据的时候,如果我只给4000地址就出错了。读不回来了。因为内部逻辑是加2,那么MPU第一次读4000(左移变成2000),第二次读诗4002(左移变成2001,而实际应当读2002)这样出问题了。就是无法连续读数据,因为真实MPU发给ASIC的地址不是按照16位增长的。
所以才问,是否可以把内部自动移位地址的这个给关闭。
在地址数据线非复用模式下是没问题的。
但是在地址数据线复用模式下就出问题了。我没办法错位地址连接,因为AD0的D0是不能错位的。
按照手册上来说,应该是可以:
按照手册上来说,应该是可以以32位的方式来访问配置成16位宽度的外部存储器的,无论它是否采用了复用方式:
不知道怎么插图稍等下
代码如下
void FSMC_SRAM_Init(void)
{
FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
FSMC_NORSRAMTimingInitTypeDef write_timing, read_timing;
GPIO_InitTypeDef GPIO_InitStructure;
/*-- GPIO Configuration ------------------------------------------------------*/
/* SRAM Data lines configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | GPIO_Pin_9 |
GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 |
GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 |
GPIO_Pin_15;
GPIO_Init(GPIOE, &GPIO_InitStructure);
/* ALE configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* NOE and NWE configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 |GPIO_Pin_5;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* NE1 configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* NBL0, NBL1 configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOE, &GPIO_InitStructure);
/*-- FSMC Configuration ------------------------------------------------------*/
write_timing.FSMC_AddressSetupTime = 0;
write_timing.FSMC_AddressHoldTime = 1;
write_timing.FSMC_DataSetupTime = 3;
write_timing.FSMC_BusTurnAroundDuration = 10;
write_timing.FSMC_CLKDivision = 0;
write_timing.FSMC_DataLatency = 0;
write_timing.FSMC_AccessMode = FSMC_AccessMode_A;
read_timing.FSMC_AddressSetupTime = 0;
read_timing.FSMC_AddressHoldTime = 1;
read_timing.FSMC_DataSetupTime = 3;
read_timing.FSMC_BusTurnAroundDuration = 10;
read_timing.FSMC_CLKDivision = 0;
read_timing.FSMC_DataLatency = 0;
read_timing.FSMC_AccessMode = FSMC_AccessMode_A;
FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1;
FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Enable;
FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_NOR;
FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_AsyncWait = FSMC_AsyncWait_Disable;
FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &write_timing;
FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &read_timing;
FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);
/* Enable FSMC Bank1_SRAM Bank */
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);
}
回路图
ASIC 可以工作在16模式下。
但每个地址 对应数据是 1byte
对十六位数据读取时
只能给出偶地址
如 0x0000
0x0002
0x0004
ASIC 可以工作在16模式下。
但每个地址 对应数据是 1byte
对十六位数据读取时
只能给出偶地址
如 0x0000
0x0002
0x0004
ASIC 可以工作在16模式下。
但每个地址 对应数据是 1byte
这段话不理解:ASIC 工作在16位模式,为什么每个地址 对应数据是 1byte,而不是1个16位的字?
你已经配置了FSMC_MemoryDataWidth_16b,也就是说每次操作(读写)外部存储器都是以16位进行的,下面我以几个例子(不考虑地址高位)说明STM32是如何操作的,看看与你看到的是否一致:
1)对地址0x0002读16位数据0x4321:
NADV=低时:AD[0] = ADDR1 = "1",AD[15:1] = ADDR[16:2] = "0"
NADV=高时:AD[0] = "1",AD[4:1] = "0",AD[5] = "1",......
2)对地址0x0002读8位数据0x21:所有的外部信号与上例相同,但在内部自动丢弃高8位数据。
2.1)对地址0x0003读8位数据0x43:所有的外部信号与上例相同,但在内部自动丢弃低8位数据。
3)对地址0x0002写16位数据0x4321:所有的外部信号与例1)相同,同时在NWE为低时,NBL1和NBL0也为低。
4)对地址0x0002写8位数据0x21:所有的外部信号与例1)相同,同时在NWE为低时,NBL0也为低。
4.1)对地址0x0003写8位数据0x43:所有的外部信号与例1)相同,同时在NWE为低时,NBL1也为低。
5)对地址0x0004读32位数据0x87654321:
5.1)先处理低16位数据 NADV=低时:AD[0] = ADDR1 = "0",AD[1] = ADDR2 = "1",AD[15:2] = ADDR[16:3] = "0"
NADV=高时:AD[15:0] = 0x4321
5.2)再处理高16位数据 NADV=低时:AD[0] = ADDR1 = "1",AD[1] = ADDR2 = "1",AD[15:2] = ADDR[16:3] = "0"
NADV=高时:AD[15:0] = 0x8765
以下黑色字体是引用LZ,蓝色字体是我的话:
**********************************************************************
如果原来是按照16BIT读,我可以自动把2000的地址编程4000进行读。
>>这里你说的"2000的地址"应该指的是memory上以16bit为单位的地址;而"编程4000进行读"应该是指STM32逻辑地址线上的以8bit为单位的地址。 这一点LZ可以确定吧?
但是如果想连续的读32bit的数据的时候,如果我只给4000地址就出错了。读不回来了。因为内部逻辑是加2,那么MPU第一次读4000(左移变成2000),第二次读诗4002(左移变成2001,而实际应当读2002)这样出问题了。就是无法连续读数据,因为真实MPU发给ASIC的地址不是按照16位增长的。
>>如果上一条LZ能确定我的理解正确,那么这里要想从4000(以8bit为单位的地址)读4个字节出来,那么按照手册上,也是我刚才的贴图上可以看到的,是分成两次16bit的读操作。第一次,以4000(以8bit为单位)读两个字节,经过所谓的地址移位,转换成LZ说的2000(以16bit为单位);第二次,读4002(以8bit为单位),"左移变成2001",就是该读2001(以16bit为单位)这个地址的两个字节。 这样就好了呀。而LZ说的"而实际应当读2002",倒是貌似理解有误也。
ASIC 可以工作在16模式下。
但每个地址 对应数据是 1byte
这段话不理解:ASIC 工作在16位模式,为什么每个地址 对应数据是 1byte,而不是1个16位的字? ...
因为 ASIC 就是这样设计的。
对奇数地址访问时禁止的。
以下红绳字体是引用LZ,蓝色字体是我的话:
**********************************************************************
如果原来是按照16BIT读,我可以自动把2000的地址编程4000进行读。
>>这里你说的"2000的地址"应该指的是memory上以16bit为单位的地址;而"编程4000进行读"应该是指STM32逻辑地址线上的以8bit为单位的地址。 这一点LZ可以确定吧?
2000的的地址是指 ASIC 8bit 地址.
但是如果想连续的读32bit的数据的时候,如果我只给4000地址就出错了。读不回来了。因为内部逻辑是加2,那么MPU第一次读4000(左移变成2000),第二次读诗4002(左移变成2001,而实际应当读2002)这样出问题了。就是无法连续读数据,因为真实MPU发给ASIC的地址不是按照16位增长的。
>>如果上一条LZ能确定我的理解正确,那么这里要想从4000(以8bit为单位的地址)读4个字节出来,那么按照手册上,也是我刚才的贴图上可以看到的,是分成两次16bit的读操作。第一次,以4000(以8bit为单位)读两个字节,经过所谓的地址移位,转换成LZ说的2000(以16bit为单位);第二次,读4002(以8bit为单位),"左移变成2001",就是该读2001(以16bit为单位)这个地址的两个字节。 这样就好了呀。而LZ说的"而实际应当读2002",倒是貌似理解有误也
问题的关键点 是ASIC的每个地址 对应数据是 1byte, 对十六位数据读取时
只能给出偶地址
如 0x0000
0x0002
0x0004
所以上边所说的读 2001情况出现的话, 读取就会出错 因为奇数地址访问是禁止的
。
大家好,我是LZ的同事
简单来说
1)ASIC只能对偶地址进行字读,不能字节读
2)ASIC的外部地址是按8位寻址的,字读的数据是由2个地址的数据组成的,连续读的偏移量应该为2(第一次2000->第二次2002)
3)MPU的外部地址是按16位寻址的,连续读的偏移量为1(第一次2000->第二次2001)
4)由2)和3)可得,第二次读的是ASIC的2001,由1)可知,不能对奇地址进行字读,出现问题
ASIC 可以工作在16模式下。
但每个地址 对应数据是 1byte
>>那么你把这个ASIC配置成8bit模式好了。你的memory每个地址对应1个字节;STM32的FSMC也不会给你进行地址移位了。