在STM32H743上解决FMC片选信号和写使能信号多次脉冲问题

#引言
在使用STM32H743的FMC(Flexible Memory Controller)时,我们可能会遇到一些问题,如单次写操作时片选信号和写使能信号出现多次脉冲。本文将介绍如何通过配置MPU(内存保护单元)和调整数据位宽来解决这些问题。

#问题描述
##问题1:片选信号多次脉冲
当没有配置MPU时,单次写操作中片选信号(NE)会出现两次脉冲。这可能导致不期望的行为和数据传输错误。

##问题2:写使能信号多次脉冲
在解决了问题1的基础上,当设置为16位数据位宽时,单次写操作会在写使能信号(FMC_NWE)上出现两次有效脉冲。通过将数据位宽设置为32位,而硬件上只对低16位IO做复用可以解决这个问题。

#解决方案
##问题1:片选信号多次脉冲
通过配置MPU,将FMC管理的存储区设置为Device或Strongly Ordered类型,禁用缓存和缓冲,可以解决片选信号多次脉冲的问题。

###配置MPU

#include "stm32h7xx_hal.h"

void MPU_Config(void) {
    MPU_Region_InitTypeDef MPU_InitStruct;

    // 禁用MPU
    HAL_MPU_Disable();

    // 配置FMC区域
    MPU_InitStruct.Enable = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress = 0x60000000;  // 这是FMC NE1的基地址,确保与实际配置匹配
    MPU_InitStruct.Size = MPU_REGION_SIZE_256MB;  // 根据实际的FMC区域大小设置
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;  // 不缓冲
    MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;    // 不缓存
    MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;        // 可共享
    MPU_InitStruct.Number = MPU_REGION_NUMBER0;  // 使用的MPU区域编号
    MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;  // 设置为Strongly Ordered
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    // 启用MPU
    HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

##问题2:写使能信号多次脉冲
在解决了片选信号问题后,通过将数据位宽设置为32位,而硬件上只对低16位IO做复用,可以解决写使能信号多次脉冲的问题。

###配置FMC和GPIO

void MX_FMC_Init(void) {
    FMC_NORSRAM_TimingTypeDef Timing;
    FMC_NORSRAM_InitTypeDef Init;

    // 配置FMC时序参数
    Timing.AddressSetupTime = 1;
    Timing.AddressHoldTime = 1;
    Timing.DataSetupTime = 2;
    Timing.BusTurnAroundDuration = 1;
    Timing.CLKDivision = 2;
    Timing.DataLatency = 2;
    Timing.AccessMode = FMC_ACCESS_MODE_A;

    // 配置FMC初始化参数
    Init.NSBank = FMC_NORSRAM_BANK1;
    Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
    Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
    Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_32; // 设置为32位数据宽度
    Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
    Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
    Init.WrapMode = FMC_WRAP_MODE_DISABLE;
    Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
    Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
    Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
    Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
    Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
    Init.WriteBurst = FMC_WRITE_BURST_DISABLE;

    // 初始化FMC
    HAL_FMC_NORSRAM_Init(&Init, &Timing);
}

void MX_GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // 启用GPIO时钟
    __HAL_RCC_GPIOF_CLK_ENABLE();
    __HAL_RCC_GPIOG_CLK_ENABLE();
    __HAL_RCC_GPIOH_CLK_ENABLE();

    // 配置低16位的数据线为FMC功能
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | 
                          GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | 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_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

    // 配置地址线和控制线
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | 
                          GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_12 | GPIO_PIN_13 | 
                          GPIO_PIN_14 | GPIO_PIN_15;
    HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | 
                          GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
    HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
}

###主程序代码

int main(void) {
    // 初始化HAL库
    HAL_Init();

    // 配置系统时钟
    SystemClock_Config();

    // 配置MPU
    MPU_Config();

    // 初始化FMC
    MX_FMC_Init();

    // 初始化GPIO
    MX_GPIO_Init();

    while (1) {
        // 执行一次写操作
        FMC_Write(0x60000000, 0x1234);
        HAL_Delay(1000); // 延迟1秒,便于观察
    }
}

// FMC写操作函数
void FMC_Write(uint32_t address, uint16_t data) {
    *(volatile uint32_t *)(address) = data; // 使用32位地址宽度,但只用低16位
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值