Skip to content

8-Bit NOR devices cause hard fault on Hal_Nor_Init #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
StephenPPEng opened this issue Apr 8, 2025 · 13 comments · May be fixed by #15
Open

8-Bit NOR devices cause hard fault on Hal_Nor_Init #14

StephenPPEng opened this issue Apr 8, 2025 · 13 comments · May be fixed by #15
Assignees
Labels
bug Something isn't working fmc Flexible Memory Controller hal HAL-LL driver-related issue or pull-request. internal bug tracker Issue confirmed and logged into the internal bug tracking system nor external NOR flash memory controller

Comments

@StephenPPEng
Copy link

StephenPPEng commented Apr 8, 2025

Describe the set-up

  • The board (either ST RPN reference or your custom board)
  • IDE or at least the compiler and its version
    Custom STM32F756BG Board.
    Macronix MX29LV040CTI (or any other 8-bit NOR flash)
    Visual Studio IDE; Code generated from STM32CubeMx.

Describe the bug
in HAL_NOR_Init, the code Hard Faults when setting the Nor ->CommandSet.
Additionally, before this, the NOR_WRITE is writing 16-bit values to a 8-bit device.

How To Reproduce
1- Spin up a project in stm32cubemx that has a NOR flash on NORSRAM_Bank_3 in Write mode (8-bit data)
2-Ensure the MPU is configured correctly
3- Generate Code
4- Run the code on a compatible board/device

  1. The modules that you suspect to be the cause of the problem (Driver, BSP, MW ...)
    HAL -> NOR

  2. The use case that generates the problem
    When running HAL_NOR_Init in the FMC for a 8-bit parallel NOR flash chip

Additional context

ISSUE1:
NOR_WRITE casts addresses to a 16-bit pointer. So when 'writing' to a 8-bit Flash, it is writing 2 bytes instead of just 1.
ISSUE2:
hnor->CommandSet = *(__IO uint16_t *) NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_ADDRESS_COMMAND_SET);
This line also has an explicit 16-bit cast. WHen working with 8-bit flash, this should be an 8-bit cast - THe 16-bit cast is causing a mis-aligned memory access when reading the command set (the address is 0x13... which is odd).
Odd-alligned memory access is prohibited for 16-bit pointers.
ISSUE3:
this section

    /* Get the value of the command set */
    if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
    {
      NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_CFI_BYTE),
                NOR_CMD_DATA_CFI);
    }
    else
    {
      NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_CFI), NOR_CMD_DATA_CFI);
    }

is meaningless as written. the NOR_ADDR_SHIFT already takes the uwNORMemoryDataWidth into account. There does not need to be 2 separate calls for 2 addresses since the NOR_ADDR_SHIFT already modifies the address.
This was a misunderstanding by me. The shift is indeed necessary.

The issues raised here have implications for the rest of the HAL NOR.
Anywhere that NOR_WRITE is used.

@StephenPPEng
Copy link
Author

My suggested fix; Or at least, something that works.

in stm32f7xx_hal_nor.c
Image

in stm32f7xx_hal_nor.h
Image

@StephenPPEng
Copy link
Author

StephenPPEng commented Apr 8, 2025

After evaluating some more, i do not see a straightforward solution to this problem.
The easiest workaround, for now, is to declare the NOR flash as a 16-bit data width, and everything appears to work flawlessly (but i have not extensively tested this).... except every other byte is 0xFF!

@ALABSTM ALABSTM added bug Something isn't working hal HAL-LL driver-related issue or pull-request. fmc Flexible Memory Controller nor external NOR flash memory controller labels Apr 9, 2025
@StephenPPEng
Copy link
Author

StephenPPEng commented Apr 9, 2025

Spent the last day looking at this;
This is all some really strange behavior...

  1. My NOR flash chip uses FUJITSU command set, and is an 8-bit data bus. However, for the CFI Read, it requires writing 0x98 to 0x55 instead of 0xAA, as seen in my code snippet above. From my understanding, this is strange behavior. My datasheet is rather confusing. 0x55 is the expected address.
  2. There are many spots in the HAL where NOR_WRITE calls must be cast to a __IO uint8_t * to prevent memory misallignment when trying to use the default __IO uint16_t *; these change must be made in the supplied HAL itself.
  3. When i identify my NOR chip as a 16-bit data bus, the commandSet reads a 0xFF02, which is obviously not the expected 0x02 of the Fujitsu command set..... however sometimes my code still runs somehow.

I'm currently in the process of modifying the HAL to correctly support both 8-bit and 16-bit data buses for my purposes. Let me know if you need any info.

@StephenPPEng
Copy link
Author

My suggested fix; Or at least, something that works.

in stm32f7xx_hal_nor.c Image

in stm32f7xx_hal_nor.h Image

Image
A cleaner version of what i had written earlier.

@KRASTM
Copy link
Contributor

KRASTM commented Apr 11, 2025

Hello @StephenPPEng,

Thank you for the report.

Regarding the issue, and after a first check in the RM0385, we have a chapter 13.5 External device address mapping at the page 312 describing how the external memory is divided into fixed-size banks of 256 Mbytes each, below an extract of the different banks and the supported memory type for each one (for the bank 3, we have only NAND flash memory):

Image

So, if you may share with us, your ioc File and the version of CubeMX you are using, we can analyze it further.

With regards,

@KRASTM KRASTM moved this from To do to In progress in stm32cube-mcu-hal-dashboard Apr 11, 2025
@KRASTM KRASTM moved this from In progress to Analyzed in stm32cube-mcu-hal-dashboard Apr 11, 2025
@StephenPPEng
Copy link
Author

StephenPPEng commented Apr 11, 2025 via email

@StephenPPEng
Copy link
Author

@KRASTM
CubeMx, 6.14.0

#MicroXplorer Configuration settings - do not modify
CAD.formats=[]
CAD.pinconfig=Dual
CAD.provider=
CORTEX_M7.AccessPermission_S-Cortex_Memory_Protection_Unit_Region1_Settings_S=MPU_REGION_FULL_ACCESS
CORTEX_M7.AccessPermission_S-Cortex_Memory_Protection_Unit_Region2_Settings_S=MPU_REGION_FULL_ACCESS
CORTEX_M7.AccessPermission_S-Cortex_Memory_Protection_Unit_Region3_Settings_S=MPU_REGION_FULL_ACCESS
CORTEX_M7.AccessPermission_S-Cortex_Memory_Protection_Unit_Region4_Settings_S=MPU_REGION_FULL_ACCESS
CORTEX_M7.BaseAddress_S-Cortex_Memory_Protection_Unit_Region1_Settings_S=0xA0000000
CORTEX_M7.BaseAddress_S-Cortex_Memory_Protection_Unit_Region2_Settings_S=0x60000000
CORTEX_M7.BaseAddress_S-Cortex_Memory_Protection_Unit_Region3_Settings_S=0x80000000
CORTEX_M7.BaseAddress_S-Cortex_Memory_Protection_Unit_Region4_Settings_S=0x68000000
CORTEX_M7.DisableExec_S-Cortex_Memory_Protection_Unit_Region1_Settings_S=MPU_INSTRUCTION_ACCESS_DISABLE
CORTEX_M7.DisableExec_S-Cortex_Memory_Protection_Unit_Region3_Settings_S=MPU_INSTRUCTION_ACCESS_DISABLE
CORTEX_M7.Enable_S-Cortex_Memory_Protection_Unit_Region1_Settings_S=MPU_REGION_ENABLE
CORTEX_M7.Enable_S-Cortex_Memory_Protection_Unit_Region2_Settings_S=MPU_REGION_ENABLE
CORTEX_M7.Enable_S-Cortex_Memory_Protection_Unit_Region3_Settings_S=MPU_REGION_ENABLE
CORTEX_M7.Enable_S-Cortex_Memory_Protection_Unit_Region4_Settings_S=MPU_REGION_ENABLE
CORTEX_M7.Enable_Spec=MPU_REGION_ENABLE
CORTEX_M7.IPParameters=default_mode_Activation,Enable_Spec,Enable_S-Cortex_Memory_Protection_Unit_Region1_Settings_S,BaseAddress_S-Cortex_Memory_Protection_Unit_Region1_Settings_S,Size_S-Cortex_Memory_Protection_Unit_Region1_Settings_S,AccessPermission_S-Cortex_Memory_Protection_Unit_Region1_Settings_S,DisableExec_S-Cortex_Memory_Protection_Unit_Region1_Settings_S,IsShareable_S-Cortex_Memory_Protection_Unit_Region1_Settings_S,Enable_S-Cortex_Memory_Protection_Unit_Region2_Settings_S,BaseAddress_S-Cortex_Memory_Protection_Unit_Region2_Settings_S,Size_S-Cortex_Memory_Protection_Unit_Region2_Settings_S,AccessPermission_S-Cortex_Memory_Protection_Unit_Region2_Settings_S,IsShareable_S-Cortex_Memory_Protection_Unit_Region2_Settings_S,Enable_S-Cortex_Memory_Protection_Unit_Region3_Settings_S,BaseAddress_S-Cortex_Memory_Protection_Unit_Region3_Settings_S,Size_S-Cortex_Memory_Protection_Unit_Region3_Settings_S,AccessPermission_S-Cortex_Memory_Protection_Unit_Region3_Settings_S,DisableExec_S-Cortex_Memory_Protection_Unit_Region3_Settings_S,IsShareable_S-Cortex_Memory_Protection_Unit_Region3_Settings_S,Enable_S-Cortex_Memory_Protection_Unit_Region4_Settings_S,BaseAddress_S-Cortex_Memory_Protection_Unit_Region4_Settings_S,Size_S-Cortex_Memory_Protection_Unit_Region4_Settings_S,IsShareable_S-Cortex_Memory_Protection_Unit_Region4_Settings_S,AccessPermission_S-Cortex_Memory_Protection_Unit_Region4_Settings_S
CORTEX_M7.IsShareable_S-Cortex_Memory_Protection_Unit_Region1_Settings_S=MPU_ACCESS_SHAREABLE
CORTEX_M7.IsShareable_S-Cortex_Memory_Protection_Unit_Region2_Settings_S=MPU_ACCESS_SHAREABLE
CORTEX_M7.IsShareable_S-Cortex_Memory_Protection_Unit_Region3_Settings_S=MPU_ACCESS_SHAREABLE
CORTEX_M7.IsShareable_S-Cortex_Memory_Protection_Unit_Region4_Settings_S=MPU_ACCESS_SHAREABLE
CORTEX_M7.Size_S-Cortex_Memory_Protection_Unit_Region1_Settings_S=MPU_REGION_SIZE_8KB
CORTEX_M7.Size_S-Cortex_Memory_Protection_Unit_Region2_Settings_S=MPU_REGION_SIZE_1MB
CORTEX_M7.Size_S-Cortex_Memory_Protection_Unit_Region3_Settings_S=MPU_REGION_SIZE_1GB
CORTEX_M7.Size_S-Cortex_Memory_Protection_Unit_Region4_Settings_S=MPU_REGION_SIZE_1MB
CORTEX_M7.default_mode_Activation=1
Dma.I2C2_TX.0.Direction=DMA_MEMORY_TO_PERIPH
Dma.I2C2_TX.0.FIFOMode=DMA_FIFOMODE_DISABLE
Dma.I2C2_TX.0.Instance=DMA1_Stream7
Dma.I2C2_TX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE
Dma.I2C2_TX.0.MemInc=DMA_MINC_ENABLE
Dma.I2C2_TX.0.Mode=DMA_NORMAL
Dma.I2C2_TX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
Dma.I2C2_TX.0.PeriphInc=DMA_PINC_DISABLE
Dma.I2C2_TX.0.Priority=DMA_PRIORITY_LOW
Dma.I2C2_TX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
Dma.Request0=I2C2_TX
Dma.RequestsNb=1
FATFS.IPParameters=_USE_LFN,_FS_EXFAT
FATFS._FS_EXFAT=1
FATFS._USE_LFN=1
FMC.AddressSetupTime3=10
FMC.AttributeSpaceHiZSetupTime1=4
FMC.AttributeSpaceHoldSetupTime1=3
FMC.AttributeSpaceSetupTime1=3
FMC.AttributeSpaceWaitSetupTime1=5
FMC.BusTurnAroundDuration1=6
FMC.BusTurnAroundDuration3=5
FMC.CommonSpaceHiZSetupTime1=4
FMC.CommonSpaceHoldSetupTime1=3
FMC.CommonSpaceSetupTime1=3
FMC.CommonSpaceWaitSetupTime1=5
FMC.DataSetupTime1=8
FMC.DataSetupTime3=20
FMC.ECCPageSize1=FMC_NAND_ECC_PAGE_SIZE_512BYTE
FMC.EccComputation1=FMC_NAND_ECC_ENABLE
FMC.IPParameters=NandPageSize1,NandSpareAreaSize1,NandBlockSize1,NandBlockNbr1,NandPlaneNbr1,NandPlaneSize1,EccComputation1,ECCPageSize1,AttributeSpaceHiZSetupTime1,AttributeSpaceSetupTime1,AttributeSpaceWaitSetupTime1,AttributeSpaceHoldSetupTime1,CommonSpaceSetupTime1,CommonSpaceWaitSetupTime1,CommonSpaceHoldSetupTime1,CommonSpaceHiZSetupTime1,TCLRSetupTime1,TARSetupTime1,DataSetupTime1,BusTurnAroundDuration1,WriteOperation1,WriteOperation3,AddressSetupTime3,DataSetupTime3,BusTurnAroundDuration3
FMC.NandBlockNbr1=8192
FMC.NandBlockSize1=64
FMC.NandPageSize1=2048
FMC.NandPlaneNbr1=2
FMC.NandPlaneSize1=4096
FMC.NandSpareAreaSize1=64
FMC.TARSetupTime1=3
FMC.TCLRSetupTime1=3
FMC.WriteOperation1=FMC_WRITE_OPERATION_ENABLE
FMC.WriteOperation3=FMC_WRITE_OPERATION_ENABLE
File.Version=6
GPIO.groupedBy=Group By Peripherals
I2C2.I2C_Speed_Mode=I2C_Fast
I2C2.IPParameters=Timing,I2C_Speed_Mode
I2C2.Timing=0x6000030D
KeepUserPlacement=false
Mcu.CPN=STM32F756BGT6
Mcu.Family=STM32F7
Mcu.IP0=CORTEX_M7
Mcu.IP1=DMA
Mcu.IP10=USB_OTG_FS
Mcu.IP2=FATFS
Mcu.IP3=FMC
Mcu.IP4=I2C2
Mcu.IP5=NVIC
Mcu.IP6=RCC
Mcu.IP7=SYS
Mcu.IP8=TIM3
Mcu.IP9=USB_HOST
Mcu.IPNb=11
Mcu.Name=STM32F756BGTx
Mcu.Package=LQFP208
Mcu.Pin0=PC15/OSC32_OUT
Mcu.Pin1=PF0
Mcu.Pin10=PH4
Mcu.Pin11=PH5
Mcu.Pin12=PF12
Mcu.Pin13=PF13
Mcu.Pin14=PF14
Mcu.Pin15=PF15
Mcu.Pin16=PG0
Mcu.Pin17=PG1
Mcu.Pin18=PE7
Mcu.Pin19=PE8
Mcu.Pin2=PF1
Mcu.Pin20=PE9
Mcu.Pin21=PE10
Mcu.Pin22=PE11
Mcu.Pin23=PE12
Mcu.Pin24=PE13
Mcu.Pin25=PE14
Mcu.Pin26=PE15
Mcu.Pin27=PD8
Mcu.Pin28=PD9
Mcu.Pin29=PD10
Mcu.Pin3=PF2
Mcu.Pin30=PD11
Mcu.Pin31=PD12
Mcu.Pin32=PD13
Mcu.Pin33=PD14
Mcu.Pin34=PD15
Mcu.Pin35=PJ11
Mcu.Pin36=PG2
Mcu.Pin37=PG3
Mcu.Pin38=PG4
Mcu.Pin39=PG5
Mcu.Pin4=PF3
Mcu.Pin40=PA8
Mcu.Pin41=PA11
Mcu.Pin42=PA12
Mcu.Pin43=PD0
Mcu.Pin44=PD1
Mcu.Pin45=PD4
Mcu.Pin46=PD5
Mcu.Pin47=PD6
Mcu.Pin48=PD7
Mcu.Pin49=PG9
Mcu.Pin5=PF4
Mcu.Pin50=PG10
Mcu.Pin51=PE0
Mcu.Pin52=PE1
Mcu.Pin53=VP_FATFS_VS_USB
Mcu.Pin54=VP_SYS_VS_Systick
Mcu.Pin55=VP_TIM3_VS_ClockSourceINT
Mcu.Pin56=VP_USB_HOST_VS_USB_HOST_MSC_FS
Mcu.Pin6=PF5
Mcu.Pin7=PH0/OSC_IN
Mcu.Pin8=PH1/OSC_OUT
Mcu.Pin9=PC0
Mcu.PinsNb=57
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F756BGTx
MxCube.Version=6.14.0
MxDb.Version=DB.6.0.140
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.DMA1_Stream7_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.ForceEnableDMAVector=true
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.I2C2_ER_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
NVIC.I2C2_EV_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.OTG_FS_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false
NVIC.TIM3_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
PA11.Mode=Host_Only
PA11.Signal=USB_OTG_FS_DM
PA12.Mode=Host_Only
PA12.Signal=USB_OTG_FS_DP
PA8.GPIOParameters=GPIO_Label
PA8.GPIO_Label=USB_FLG
PA8.Locked=true
PA8.Signal=GPIO_Input
PC0.GPIOParameters=GPIO_Label
PC0.GPIO_Label=USB_VBUS_EN
PC0.Locked=true
PC0.Signal=GPIO_Output
PC15/OSC32_OUT.GPIOParameters=PinState,GPIO_Label
PC15/OSC32_OUT.GPIO_Label=FMC_NAND_NWP
PC15/OSC32_OUT.Locked=true
PC15/OSC32_OUT.PinState=GPIO_PIN_RESET
PC15/OSC32_OUT.Signal=GPIO_Output
PD0.GPIOParameters=GPIO_PuPd
PD0.GPIO_PuPd=GPIO_PULLUP
PD0.Signal=FMC_D2_DA2
PD1.GPIOParameters=GPIO_PuPd
PD1.GPIO_PuPd=GPIO_PULLUP
PD1.Signal=FMC_D3_DA3
PD10.GPIOParameters=GPIO_PuPd
PD10.GPIO_PuPd=GPIO_PULLUP
PD10.Signal=FMC_D15_DA15
PD11.GPIOParameters=GPIO_PuPd
PD11.GPIO_PuPd=GPIO_PULLUP
PD11.Signal=FMC_A16_CLE
PD12.GPIOParameters=GPIO_PuPd
PD12.GPIO_PuPd=GPIO_PULLUP
PD12.Signal=FMC_A17_ALE
PD13.GPIOParameters=GPIO_PuPd
PD13.GPIO_PuPd=GPIO_PULLUP
PD13.Signal=FMC_A18
PD14.GPIOParameters=GPIO_PuPd
PD14.GPIO_PuPd=GPIO_PULLUP
PD14.Signal=FMC_D0_DA0
PD15.GPIOParameters=GPIO_PuPd
PD15.GPIO_PuPd=GPIO_PULLUP
PD15.Signal=FMC_D1_DA1
PD4.GPIOParameters=GPIO_PuPd
PD4.GPIO_PuPd=GPIO_NOPULL
PD4.Signal=FMC_NOE
PD5.GPIOParameters=GPIO_PuPd
PD5.GPIO_PuPd=GPIO_PULLUP
PD5.Signal=FMC_NWE
PD6.GPIOParameters=GPIO_PuPd
PD6.GPIO_PuPd=GPIO_PULLUP
PD6.Locked=true
PD6.Signal=FMC_NWAIT
PD7.GPIOParameters=GPIO_PuPd
PD7.GPIO_PuPd=GPIO_PULLUP
PD7.Mode=NorPsramChipSelect1_1
PD7.Signal=FMC_NE1
PD8.GPIOParameters=GPIO_PuPd
PD8.GPIO_PuPd=GPIO_PULLUP
PD8.Signal=FMC_D13_DA13
PD9.GPIOParameters=GPIO_PuPd
PD9.GPIO_PuPd=GPIO_PULLUP
PD9.Signal=FMC_D14_DA14
PE0.GPIOParameters=GPIO_PuPd
PE0.GPIO_PuPd=GPIO_PULLUP
PE0.Locked=true
PE0.Signal=FMC_NBL0
PE1.GPIOParameters=GPIO_PuPd
PE1.GPIO_PuPd=GPIO_PULLUP
PE1.Locked=true
PE1.Signal=FMC_NBL1
PE10.GPIOParameters=GPIO_PuPd
PE10.GPIO_PuPd=GPIO_PULLUP
PE10.Signal=FMC_D7_DA7
PE11.GPIOParameters=GPIO_PuPd,GPIO_Mode
PE11.GPIO_Mode=GPIO_MODE_AF_PP
PE11.GPIO_PuPd=GPIO_PULLUP
PE11.Signal=FMC_D8_DA8
PE12.GPIOParameters=GPIO_PuPd,GPIO_Mode
PE12.GPIO_Mode=GPIO_MODE_AF_PP
PE12.GPIO_PuPd=GPIO_PULLUP
PE12.Signal=FMC_D9_DA9
PE13.GPIOParameters=GPIO_PuPd,GPIO_Mode
PE13.GPIO_Mode=GPIO_MODE_AF_PP
PE13.GPIO_PuPd=GPIO_PULLUP
PE13.Signal=FMC_D10_DA10
PE14.GPIOParameters=GPIO_PuPd,GPIO_Mode
PE14.GPIO_Mode=GPIO_MODE_AF_PP
PE14.GPIO_PuPd=GPIO_PULLUP
PE14.Signal=FMC_D11_DA11
PE15.GPIOParameters=GPIO_PuPd,GPIO_Mode
PE15.GPIO_Mode=GPIO_MODE_AF_PP
PE15.GPIO_PuPd=GPIO_PULLUP
PE15.Signal=FMC_D12_DA12
PE7.GPIOParameters=GPIO_PuPd
PE7.GPIO_PuPd=GPIO_PULLUP
PE7.Signal=FMC_D4_DA4
PE8.GPIOParameters=GPIO_PuPd
PE8.GPIO_PuPd=GPIO_PULLUP
PE8.Signal=FMC_D5_DA5
PE9.GPIOParameters=GPIO_PuPd
PE9.GPIO_PuPd=GPIO_PULLUP
PE9.Signal=FMC_D6_DA6
PF0.GPIOParameters=GPIO_PuPd
PF0.GPIO_PuPd=GPIO_PULLUP
PF0.Signal=FMC_A0
PF1.GPIOParameters=GPIO_PuPd
PF1.GPIO_PuPd=GPIO_PULLUP
PF1.Signal=FMC_A1
PF12.GPIOParameters=GPIO_PuPd
PF12.GPIO_PuPd=GPIO_PULLUP
PF12.Signal=FMC_A6
PF13.GPIOParameters=GPIO_PuPd
PF13.GPIO_PuPd=GPIO_PULLUP
PF13.Signal=FMC_A7
PF14.GPIOParameters=GPIO_PuPd
PF14.GPIO_PuPd=GPIO_PULLUP
PF14.Signal=FMC_A8
PF15.GPIOParameters=GPIO_PuPd
PF15.GPIO_PuPd=GPIO_PULLUP
PF15.Signal=FMC_A9
PF2.GPIOParameters=GPIO_PuPd
PF2.GPIO_PuPd=GPIO_PULLUP
PF2.Signal=FMC_A2
PF3.GPIOParameters=GPIO_PuPd
PF3.GPIO_PuPd=GPIO_PULLUP
PF3.Signal=FMC_A3
PF4.GPIOParameters=GPIO_PuPd
PF4.GPIO_PuPd=GPIO_PULLUP
PF4.Signal=FMC_A4
PF5.GPIOParameters=GPIO_PuPd
PF5.GPIO_PuPd=GPIO_PULLUP
PF5.Signal=FMC_A5
PG0.GPIOParameters=GPIO_PuPd
PG0.GPIO_PuPd=GPIO_PULLUP
PG0.Signal=FMC_A10
PG1.GPIOParameters=GPIO_PuPd
PG1.GPIO_PuPd=GPIO_PULLUP
PG1.Signal=FMC_A11
PG10.GPIOParameters=GPIO_PuPd
PG10.GPIO_PuPd=GPIO_NOPULL
PG10.Mode=NorPsramChipSelect3_3
PG10.Signal=FMC_NE3
PG2.GPIOParameters=GPIO_PuPd
PG2.GPIO_PuPd=GPIO_PULLUP
PG2.Signal=FMC_A12
PG3.GPIOParameters=GPIO_PuPd
PG3.GPIO_PuPd=GPIO_PULLUP
PG3.Signal=FMC_A13
PG4.GPIOParameters=GPIO_PuPd
PG4.GPIO_PuPd=GPIO_PULLUP
PG4.Signal=FMC_A14_BA0
PG5.GPIOParameters=GPIO_PuPd
PG5.GPIO_PuPd=GPIO_PULLUP
PG5.Signal=FMC_A15_BA1
PG9.GPIOParameters=GPIO_PuPd
PG9.GPIO_PuPd=GPIO_PULLUP
PG9.Mode=NandChipSelect3_1
PG9.Signal=FMC_NCE
PH0/OSC_IN.Mode=HSE-External-Oscillator
PH0/OSC_IN.Signal=RCC_OSC_IN
PH1/OSC_OUT.Mode=HSE-External-Oscillator
PH1/OSC_OUT.Signal=RCC_OSC_OUT
PH4.GPIOParameters=GPIO_Pu
PH4.GPIO_Pu=GPIO_PULLUP
PH4.Mode=I2C
PH4.Signal=I2C2_SCL
PH5.GPIOParameters=GPIO_Pu
PH5.GPIO_Pu=GPIO_PULLUP
PH5.Mode=I2C
PH5.Signal=I2C2_SDA
PJ11.GPIOParameters=PinState,GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultOutputPP
PJ11.GPIO_Label=LED_EN
PJ11.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
PJ11.GPIO_PuPd=GPIO_PULLUP
PJ11.Locked=true
PJ11.PinState=GPIO_PIN_SET
PJ11.Signal=GPIO_Output
PinOutPanel.RotationAngle=0
ProjectManager.AskForMigrate=true
ProjectManager.BackupPrevious=false
ProjectManager.CompilerLinker=GCC
ProjectManager.CompilerOptimize=6
ProjectManager.ComputerToolchain=false
ProjectManager.CoupleFile=true
ProjectManager.CustomerFirmwarePackage=
ProjectManager.DefaultFWLocation=true
ProjectManager.DeletePrevious=false
ProjectManager.DeviceId=STM32F756BGTx
ProjectManager.FirmwarePackage=STM32Cube FW_F7 V1.17.2
ProjectManager.FreePins=false
ProjectManager.HalAssertFull=false
ProjectManager.HeapSize=0x200
ProjectManager.KeepUserCode=true
ProjectManager.LastFirmware=true
ProjectManager.LibraryCopy=0
ProjectManager.MainLocation=Core/Src
ProjectManager.NoMain=false
ProjectManager.PreviousToolchain=STM32CubeIDE
ProjectManager.ProjectBuild=false
ProjectManager.ProjectFileName=nemo_bl.ioc
ProjectManager.ProjectName=nemo_bl
ProjectManager.ProjectStructure=
ProjectManager.RegisterCallBack=
ProjectManager.StackSize=0x400
ProjectManager.TargetToolchain=CMake
ProjectManager.ToolChainLocation=
ProjectManager.UAScriptAfterPath=convertLineEndings.sh
ProjectManager.UAScriptBeforePath=
ProjectManager.UnderRoot=false
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_FMC_Init-FMC-false-HAL-true,5-MX_FATFS_Init-FATFS-false-HAL-false,6-MX_USB_HOST_Init-USB_HOST-false-HAL-false,7-MX_I2C2_Init-I2C2-false-HAL-true,8-MX_TIM3_Init-TIM3-false-HAL-true,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true
RCC.AHBFreq_Value=216000000
RCC.APB1CLKDivider=RCC_HCLK_DIV4
RCC.APB1Freq_Value=54000000
RCC.APB1TimFreq_Value=108000000
RCC.APB2CLKDivider=RCC_HCLK_DIV2
RCC.APB2Freq_Value=108000000
RCC.APB2TimFreq_Value=216000000
RCC.CECFreq_Value=32786.88524590164
RCC.CortexFreq_Value=216000000
RCC.EthernetFreq_Value=216000000
RCC.FCLKCortexFreq_Value=216000000
RCC.FamilyName=M
RCC.HCLKFreq_Value=216000000
RCC.HSE_VALUE=16000000
RCC.HSI_VALUE=16000000
RCC.I2C1Freq_Value=54000000
RCC.I2C2Freq_Value=54000000
RCC.I2C3Freq_Value=54000000
RCC.I2C4Freq_Value=54000000
RCC.I2SFreq_Value=192000000
RCC.IPParameters=AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2CLKDivider,APB2Freq_Value,APB2TimFreq_Value,CECFreq_Value,CortexFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I2SFreq_Value,LCDTFToutputFreq_Value,LPTIM1Freq_Value,LSE_VALUE,LSI_VALUE,MCO2PinFreq_Value,PLLCLKFreq_Value,PLLI2SPCLKFreq_Value,PLLI2SQCLKFreq_Value,PLLI2SRCLKFreq_Value,PLLI2SRoutputFreq_Value,PLLM,PLLN,PLLQ,PLLQCLKFreq_Value,PLLQoutputFreq_Value,PLLSAIPCLKFreq_Value,PLLSAIQCLKFreq_Value,PLLSAIRCLKFreq_Value,PLLSAIoutputFreq_Value,RNGFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,UART4Freq_Value,UART5Freq_Value,UART7Freq_Value,UART8Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USART6Freq_Value,USBFreq_Value,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VCOSAIOutputFreq_Value
RCC.LCDTFToutputFreq_Value=96000000
RCC.LPTIM1Freq_Value=54000000
RCC.LSE_VALUE=32768
RCC.LSI_VALUE=32000
RCC.MCO2PinFreq_Value=216000000
RCC.PLLCLKFreq_Value=216000000
RCC.PLLI2SPCLKFreq_Value=192000000
RCC.PLLI2SQCLKFreq_Value=192000000
RCC.PLLI2SRCLKFreq_Value=192000000
RCC.PLLI2SRoutputFreq_Value=192000000
RCC.PLLM=8
RCC.PLLN=216
RCC.PLLQ=9
RCC.PLLQCLKFreq_Value=48000000
RCC.PLLQoutputFreq_Value=48000000
RCC.PLLSAIPCLKFreq_Value=192000000
RCC.PLLSAIQCLKFreq_Value=192000000
RCC.PLLSAIRCLKFreq_Value=192000000
RCC.PLLSAIoutputFreq_Value=192000000
RCC.RNGFreq_Value=48000000
RCC.SAI1Freq_Value=192000000
RCC.SAI2Freq_Value=192000000
RCC.SDMMCFreq_Value=216000000
RCC.SPDIFRXFreq_Value=192000000
RCC.SYSCLKFreq_VALUE=216000000
RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
RCC.UART4Freq_Value=54000000
RCC.UART5Freq_Value=54000000
RCC.UART7Freq_Value=54000000
RCC.UART8Freq_Value=54000000
RCC.USART1Freq_Value=108000000
RCC.USART2Freq_Value=54000000
RCC.USART3Freq_Value=54000000
RCC.USART6Freq_Value=108000000
RCC.USBFreq_Value=48000000
RCC.VCOI2SOutputFreq_Value=384000000
RCC.VCOInputFreq_Value=2000000
RCC.VCOOutputFreq_Value=432000000
RCC.VCOSAIOutputFreq_Value=384000000
SH.FMC_A0.0=FMC_A0,19b-a1
SH.FMC_A0.1=FMC_A0,19b-a3
SH.FMC_A0.ConfNb=2
SH.FMC_A1.0=FMC_A1,19b-a1
SH.FMC_A1.1=FMC_A1,19b-a3
SH.FMC_A1.ConfNb=2
SH.FMC_A10.0=FMC_A10,19b-a1
SH.FMC_A10.1=FMC_A10,19b-a3
SH.FMC_A10.ConfNb=2
SH.FMC_A11.0=FMC_A11,19b-a1
SH.FMC_A11.1=FMC_A11,19b-a3
SH.FMC_A11.ConfNb=2
SH.FMC_A12.0=FMC_A12,19b-a1
SH.FMC_A12.1=FMC_A12,19b-a3
SH.FMC_A12.ConfNb=2
SH.FMC_A13.0=FMC_A13,19b-a1
SH.FMC_A13.1=FMC_A13,19b-a3
SH.FMC_A13.ConfNb=2
SH.FMC_A14_BA0.0=FMC_A14,19b-a1
SH.FMC_A14_BA0.1=FMC_A14,19b-a3
SH.FMC_A14_BA0.ConfNb=2
SH.FMC_A15_BA1.0=FMC_A15,19b-a1
SH.FMC_A15_BA1.1=FMC_A15,19b-a3
SH.FMC_A15_BA1.ConfNb=2
SH.FMC_A16_CLE.0=FMC_CLE,8b-dmux1
SH.FMC_A16_CLE.1=FMC_A16,19b-a1
SH.FMC_A16_CLE.2=FMC_A16,19b-a3
SH.FMC_A16_CLE.ConfNb=3
SH.FMC_A17_ALE.0=FMC_ALE,8b-dmux1
SH.FMC_A17_ALE.1=FMC_A17,19b-a1
SH.FMC_A17_ALE.2=FMC_A17,19b-a3
SH.FMC_A17_ALE.ConfNb=3
SH.FMC_A18.0=FMC_A18,19b-a1
SH.FMC_A18.1=FMC_A18,19b-a3
SH.FMC_A18.ConfNb=2
SH.FMC_A2.0=FMC_A2,19b-a1
SH.FMC_A2.1=FMC_A2,19b-a3
SH.FMC_A2.ConfNb=2
SH.FMC_A3.0=FMC_A3,19b-a1
SH.FMC_A3.1=FMC_A3,19b-a3
SH.FMC_A3.ConfNb=2
SH.FMC_A4.0=FMC_A4,19b-a1
SH.FMC_A4.1=FMC_A4,19b-a3
SH.FMC_A4.ConfNb=2
SH.FMC_A5.0=FMC_A5,19b-a1
SH.FMC_A5.1=FMC_A5,19b-a3
SH.FMC_A5.ConfNb=2
SH.FMC_A6.0=FMC_A6,19b-a1
SH.FMC_A6.1=FMC_A6,19b-a3
SH.FMC_A6.ConfNb=2
SH.FMC_A7.0=FMC_A7,19b-a1
SH.FMC_A7.1=FMC_A7,19b-a3
SH.FMC_A7.ConfNb=2
SH.FMC_A8.0=FMC_A8,19b-a1
SH.FMC_A8.1=FMC_A8,19b-a3
SH.FMC_A8.ConfNb=2
SH.FMC_A9.0=FMC_A9,19b-a1
SH.FMC_A9.1=FMC_A9,19b-a3
SH.FMC_A9.ConfNb=2
SH.FMC_D0_DA0.0=FMC_D0,8b-dmux1
SH.FMC_D0_DA0.1=FMC_D0,16b-d1
SH.FMC_D0_DA0.2=FMC_D0,8b-d3
SH.FMC_D0_DA0.ConfNb=3
SH.FMC_D10_DA10.0=FMC_D10,16b-d1
SH.FMC_D10_DA10.ConfNb=1
SH.FMC_D11_DA11.0=FMC_D11,16b-d1
SH.FMC_D11_DA11.ConfNb=1
SH.FMC_D12_DA12.0=FMC_D12,16b-d1
SH.FMC_D12_DA12.ConfNb=1
SH.FMC_D13_DA13.0=FMC_D13,16b-d1
SH.FMC_D13_DA13.ConfNb=1
SH.FMC_D14_DA14.0=FMC_D14,16b-d1
SH.FMC_D14_DA14.ConfNb=1
SH.FMC_D15_DA15.0=FMC_D15,16b-d1
SH.FMC_D15_DA15.ConfNb=1
SH.FMC_D1_DA1.0=FMC_D1,8b-dmux1
SH.FMC_D1_DA1.1=FMC_D1,16b-d1
SH.FMC_D1_DA1.2=FMC_D1,8b-d3
SH.FMC_D1_DA1.ConfNb=3
SH.FMC_D2_DA2.0=FMC_D2,8b-dmux1
SH.FMC_D2_DA2.1=FMC_D2,16b-d1
SH.FMC_D2_DA2.2=FMC_D2,8b-d3
SH.FMC_D2_DA2.ConfNb=3
SH.FMC_D3_DA3.0=FMC_D3,8b-dmux1
SH.FMC_D3_DA3.1=FMC_D3,16b-d1
SH.FMC_D3_DA3.2=FMC_D3,8b-d3
SH.FMC_D3_DA3.ConfNb=3
SH.FMC_D4_DA4.0=FMC_D4,8b-dmux1
SH.FMC_D4_DA4.1=FMC_D4,16b-d1
SH.FMC_D4_DA4.2=FMC_D4,8b-d3
SH.FMC_D4_DA4.ConfNb=3
SH.FMC_D5_DA5.0=FMC_D5,8b-dmux1
SH.FMC_D5_DA5.1=FMC_D5,16b-d1
SH.FMC_D5_DA5.2=FMC_D5,8b-d3
SH.FMC_D5_DA5.ConfNb=3
SH.FMC_D6_DA6.0=FMC_D6,8b-dmux1
SH.FMC_D6_DA6.1=FMC_D6,16b-d1
SH.FMC_D6_DA6.2=FMC_D6,8b-d3
SH.FMC_D6_DA6.ConfNb=3
SH.FMC_D7_DA7.0=FMC_D7,8b-dmux1
SH.FMC_D7_DA7.1=FMC_D7,16b-d1
SH.FMC_D7_DA7.2=FMC_D7,8b-d3
SH.FMC_D7_DA7.ConfNb=3
SH.FMC_D8_DA8.0=FMC_D8,16b-d1
SH.FMC_D8_DA8.ConfNb=1
SH.FMC_D9_DA9.0=FMC_D9,16b-d1
SH.FMC_D9_DA9.ConfNb=1
SH.FMC_NBL0.0=FMC_NBL0,2ByteEnable1
SH.FMC_NBL0.ConfNb=1
SH.FMC_NBL1.0=FMC_NBL1,2ByteEnable1
SH.FMC_NBL1.ConfNb=1
SH.FMC_NOE.0=FMC_NOE,8b-dmux1
SH.FMC_NOE.1=FMC_NOE,Psram1
SH.FMC_NOE.2=FMC_NOE,NorFlash3
SH.FMC_NOE.ConfNb=3
SH.FMC_NWAIT.0=FMC_NWAIT,Wait1
SH.FMC_NWAIT.ConfNb=1
SH.FMC_NWE.0=FMC_NWE,8b-dmux1
SH.FMC_NWE.1=FMC_NWE,Psram1
SH.FMC_NWE.2=FMC_NWE,NorFlash3
SH.FMC_NWE.ConfNb=3
TIM3.IPParameters=Period,Prescaler
TIM3.Period=5000
TIM3.Prescaler=10799
USB_HOST.IPParameters=USBH_HandleTypeDef-MSC_FS,VirtualModeFS,SW_VBUS_DRIVE_MSC_FS
USB_HOST.SW_VBUS_DRIVE_MSC_FS=true
USB_HOST.USBH_HandleTypeDef-MSC_FS=hUsbHostFS
USB_HOST.VirtualModeFS=Msc
USB_OTG_FS.IPParameters=VirtualMode,phy_itface,speed
USB_OTG_FS.VirtualMode=Host_Only
USB_OTG_FS.phy_itface=HCD_PHY_EMBEDDED
USB_OTG_FS.speed=HCD_SPEED_FULL
VP_FATFS_VS_USB.Mode=USB
VP_FATFS_VS_USB.Signal=FATFS_VS_USB
VP_SYS_VS_Systick.Mode=SysTick
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
VP_TIM3_VS_ClockSourceINT.Mode=Internal
VP_TIM3_VS_ClockSourceINT.Signal=TIM3_VS_ClockSourceINT
VP_USB_HOST_VS_USB_HOST_MSC_FS.Mode=MSC_FS
VP_USB_HOST_VS_USB_HOST_MSC_FS.Signal=USB_HOST_VS_USB_HOST_MSC_FS
board=custom

Additionally, here is the final version of how to get the Command Set (notice the 8-bit NOR_WRITE). This can always be 8-bit because the standard incicates that the return value for the command set will be 1 byte.

Image

@StephenPPEng
Copy link
Author

So what I've found in my testing:

The NOR_WRITE() function needs to match the size of the Data Width.
If Data Width is 8-bits, then the NOR_WRITE() needs to cast to a (__IO uint8_t *).
If 16-bits, then the NOR_WRITE() needs to cast to a (__IO uint16_t *).
etc.

The NOR_ADDR_SHIFT already does the job of moving the correct value to the right spot. There does not need to be "special" 8-bit vs 16-bit command bytes.

Generated Code for HAL_NOR_Init():
Image
Issues are circled.

Green: This should be an 8-bit NOR_WRITE() instead of a 16-bit NOR_WRITE(). Since 8-bit addresses can be odd, using a 16-bit NOR_WRITE() here could/will cause an Unalligned Memory Access fault.

Red: This should be NOR_CMD_ADDRESS_FIRST_CFI. It SHOULD NOT be NOR_CMD_ADDRESS_FIRST_CFI_BYTE because the NOR_ADDR_SHIFT handles shifting the address to the correct bits. (The correct address to Write to for this command is 0x55, not 0xAA, according to the CFI Spec Document)

Blue: Any time values are READ from NOR, the address to read should be casted to the appropriate sized pointer. Here, it is always cast as a 16-bit pointer. This is a problem. Another option is to ALWAYS use an 8-bit pointer. Well now you are only getting 1 byte on a 16-bit data bus.

Device Type / Mode Result
x8 Device / x8 Read / Odd Address No fault. Works as expected. Read will retrieve 1 byte from NOR and put 1 byte into the buffer.
x8 Device / x8 Read / Even Address No fault. Works as expected Read will retrieve 1 byte from NOR and put 1 byte into the buffer.
x8 Device / x16 Read / Odd Address Misalligned Memory Access Fault
x8 Device / x16 Read / Even Address No fault. Value must be masked off with val & 0xFF to ensure upper trash byte is not forwarded
x16 Device / x8 Read / Odd Address No Fault. But you are sending an odd address to a 16-bit device, so behavior may be device-dependent. My device simply removed the LSb from the address to make it even and then returned that value. But the buffer will only be filled with 1 byte, instead of the expected 2 bytes.
x16 Device / x8 Read / Even Address No Fault. But the buffer will only be filled with 1 byte instead of the expected 2 bytes.
x16 Device / x16 Read / Odd Address No Fault. Works as expected. Read will retrieve 2 bytes from NOR and put 2 bytes into the buffer.
x16 Device / x16 Read / Even Address No Fault. Works as expected. Read will retrieve 2 bytes from NOR and put 2 bytes into the buffer.

@StephenPPEng
Copy link
Author

StephenPPEng commented Apr 14, 2025

TL;DR:
Original Generated Code for the end of the HAL_NOR_Init():

//...
else
  {
    /* Get the value of the command set */
    if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
    {
      NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_CFI_BYTE),
                NOR_CMD_DATA_CFI);
    }
    else
    {
      NOR_WRITE(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_CFI), NOR_CMD_DATA_CFI);
    }

    hnor->CommandSet = *(__IO uint16_t *) NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_ADDRESS_COMMAND_SET);

    status = HAL_NOR_ReturnToReadMode(hnor);
  }
//...

My suggested change:

//...
else
  {
    /* Get the value of the command set */
    NOR_WRITE_8b(NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST_CFI), 
                NOR_CMD_DATA_CFI);
    hnor->CommandSet = *(__IO uint8_t *)NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_ADDRESS_COMMAND_SET);

    status = HAL_NOR_ReturnToReadMode(hnor);
  }
//...
/**
  * @brief  NOR memory write 8-bit data to specified address.
  * @param  __ADDRESS__ NOR memory address
  * @param  __DATA__ Data to write
  * @retval None
  */
#define NOR_WRITE_8b(__ADDRESS__, __DATA__)   do{                                                             \
                                               (*(__IO uint8_t *)((uint32_t)(__ADDRESS__)) = (__DATA__)); \
                                               __DSB();                                                    \
                                             } while(0)

And this needs to be done everywhere in the HAL_NOR file.

To support different data types, HAL_NOR_Read() and HAL_NOR_Program() must have their signatures changed to the following

HAL_StatusTypeDef HAL_NOR_Read(NOR_HandleTypeDef *hnor, uint32_t *pAddress, uint16_t *pData);
becomes
HAL_StatusTypeDef HAL_NOR_Read(NOR_HandleTypeDef *hnor, uint8_t *pAddress, void *pData);

and
HAL_StatusTypeDef HAL_NOR_Program(NOR_HandleTypeDef *hnor, uint32_t *pAddress, uint16_t *pData);
becomes
HAL_StatusTypeDef HAL_NOR_Program(NOR_HandleTypeDef *hnor, uint8_t *pAddress, uint32_t Data);

@KRASTM
Copy link
Contributor

KRASTM commented Apr 15, 2025

Hello @StephenPPEng,

Thanks for the details, I will forward your suggestion to our team.

With regards,

@KRASTM
Copy link
Contributor

KRASTM commented Apr 15, 2025

ST Internal Reference: 207766

@KRASTM KRASTM added the internal bug tracker Issue confirmed and logged into the internal bug tracking system label Apr 15, 2025
@StephenPPEng
Copy link
Author

StephenPPEng commented Apr 15, 2025

For another reference, here is what my HAL_NOR_Program() looks like

/**
  * @brief  Program data to NOR memory
  * @param  hnor pointer to a NOR_HandleTypeDef structure that contains
  *                the configuration information for NOR module.
  * @param  pAddress Device address
  * @param  data the data to be programmed
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_NOR_Program(NOR_HandleTypeDef *hnor, uint8_t *pAddress, uint32_t data)
{
  uint32_t deviceaddress;
  HAL_StatusTypeDef status = HAL_OK;

  /* Check the NOR controller state */
  if (hnor->State == HAL_NOR_STATE_BUSY)
  {
    return HAL_BUSY;
  }
  else if (hnor->State == HAL_NOR_STATE_READY)
  {
    /* Process Locked */
    __HAL_LOCK(hnor);

    /* Update the NOR controller state */
    hnor->State = HAL_NOR_STATE_BUSY;

    /* Select the NOR device address */
    if (hnor->Init.NSBank == FMC_NORSRAM_BANK1)
    {
      deviceaddress = NOR_MEMORY_ADRESS1;
    }
    else if (hnor->Init.NSBank == FMC_NORSRAM_BANK2)
    {
      deviceaddress = NOR_MEMORY_ADRESS2;
    }
    else if (hnor->Init.NSBank == FMC_NORSRAM_BANK3)
    {
      deviceaddress = NOR_MEMORY_ADRESS3;
    }
    else /* FMC_NORSRAM_BANK4 */
    {
      deviceaddress = NOR_MEMORY_ADRESS4;
    }

    /* Send program data command */
    if (hnor->CommandSet == NOR_AMD_FUJITSU_COMMAND_SET)
    {
      uint32_t cycle1Addr = NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST);
      uint32_t cycle2Addr = NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND);
      uint32_t cycle3Addr = NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD);
      if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
      {
        NOR_WRITE_8b(cycle1Addr, NOR_CMD_DATA_FIRST);
        NOR_WRITE_8b(cycle2Addr, NOR_CMD_DATA_SECOND);
        NOR_WRITE_8b(cycle3Addr, NOR_CMD_DATA_PROGRAM);
      }
      else
      {
        NOR_WRITE(cycle1Addr, NOR_CMD_DATA_FIRST);
        NOR_WRITE(cycle2Addr, NOR_CMD_DATA_SECOND);
        NOR_WRITE(cycle3Addr, NOR_CMD_DATA_PROGRAM);
      }
    }
    else if (hnor->CommandSet == NOR_INTEL_SHARP_EXT_COMMAND_SET)
    {
      NOR_WRITE(pAddress, NOR_CMD_WORD_PROGRAM);
    }
    else
    {
      /* Primary command set not supported by the driver */
      status = HAL_ERROR;
    }

    if (status != HAL_ERROR)
    {
      /* Write the data */
      if(uwNORMemoryDataWidth == NOR_MEMORY_8B)
      {
        NOR_WRITE_8b(pAddress, data & 0xFF);
      }
      else
      {
        pAddress = (uint8_t *)((uint32_t)pAddress & 0xFFFFFFFE); /* Address must be even for 16 bits access */
        NOR_WRITE(pAddress, data & 0xFFFF);
      }
    }
    
    /* Check the NOR controller state */
    hnor->State = HAL_NOR_STATE_READY;

    /* Process unlocked */
    __HAL_UNLOCK(hnor);
  }
  else
  {
    return HAL_ERROR;
  }

  return status;
}

And my HAL_NOR_Read()

/**
  * @brief  Read data from NOR memory
  * @param  hnor pointer to a NOR_HandleTypeDef structure that contains
  *                the configuration information for NOR module.
  * @param  pAddress pointer to Device address
  * @param  pData  pointer to read data
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_NOR_Read(NOR_HandleTypeDef *hnor, uint8_t *pAddress, void *pData)
{
  uint32_t deviceaddress;
  HAL_NOR_StateTypeDef state;
  HAL_StatusTypeDef status = HAL_OK;
  if(pData == NULL)
  {
    return HAL_ERROR;
  }

  /* Check the NOR controller state */
  state = hnor->State;
  if (state == HAL_NOR_STATE_BUSY)
  {
    return HAL_BUSY;
  }
  else if (state == HAL_NOR_STATE_PROTECTED)
  {
    return HAL_ERROR;
  }
  else if (state == HAL_NOR_STATE_READY)
  {
    /* Process Locked */
    __HAL_LOCK(hnor);

    /* Update the NOR controller state */
    hnor->State = HAL_NOR_STATE_BUSY;

    /* Select the NOR device address */
    if (hnor->Init.NSBank == FMC_NORSRAM_BANK1)
    {
      deviceaddress = NOR_MEMORY_ADRESS1;
    }
    else if (hnor->Init.NSBank == FMC_NORSRAM_BANK2)
    {
      deviceaddress = NOR_MEMORY_ADRESS2;
    }
    else if (hnor->Init.NSBank == FMC_NORSRAM_BANK3)
    {
      deviceaddress = NOR_MEMORY_ADRESS3;
    }
    else /* FMC_NORSRAM_BANK4 */
    {
      deviceaddress = NOR_MEMORY_ADRESS4;
    }

    /* Send read data command */
    if (hnor->CommandSet == NOR_AMD_FUJITSU_COMMAND_SET)
    {
      uint32_t cycle1Addr = NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_FIRST);
      uint32_t cycle2Addr = NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_SECOND);
      uint32_t cycle3Addr = NOR_ADDR_SHIFT(deviceaddress, uwNORMemoryDataWidth, NOR_CMD_ADDRESS_THIRD);

      if (uwNORMemoryDataWidth == NOR_MEMORY_8B)
      {
        NOR_WRITE_8b(cycle1Addr, NOR_CMD_DATA_FIRST);
        NOR_WRITE_8b(cycle2Addr, NOR_CMD_DATA_SECOND);
        NOR_WRITE_8b(cycle3Addr, NOR_CMD_DATA_READ_RESET);
      }
      else
      {
        NOR_WRITE(cycle1Addr, NOR_CMD_DATA_FIRST);
        NOR_WRITE(cycle2Addr, NOR_CMD_DATA_SECOND);
        NOR_WRITE(cycle3Addr, NOR_CMD_DATA_READ_RESET);
      }
    }
    else if (hnor->CommandSet == NOR_INTEL_SHARP_EXT_COMMAND_SET)
    {
      NOR_WRITE(pAddress, NOR_CMD_READ_ARRAY);
    }
    else
    {
      /* Primary command set not supported by the driver */
      status = HAL_ERROR;
    }

    if (status != HAL_ERROR)
    {
      /* Read the data */
      if(uwNORMemoryDataWidth == NOR_MEMORY_8B)
      {
        *(uint8_t *)pData = (uint8_t)(*(__IO uint8_t *)pAddress);
      }
      else
      {
        /* Address must be even for 16 bits access */
        pAddress = (uint8_t *)((uint32_t)pAddress & 0xFFFFFFFE); 

        *(uint16_t *)pData = (uint16_t)(*(__IO uint16_t *)pAddress);
      }
    }

    /* Check the NOR controller state */
    hnor->State = state;

    /* Process unlocked */
    __HAL_UNLOCK(hnor);
  }
  else
  {
    return HAL_ERROR;
  }

  return status;
}

Also note:
I only have experience with the AMD command set. Likely the other comand set will need to updated with similar functionality

@StephenPPEng
Copy link
Author

I'm putting together a pull request for this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working fmc Flexible Memory Controller hal HAL-LL driver-related issue or pull-request. internal bug tracker Issue confirmed and logged into the internal bug tracking system nor external NOR flash memory controller
Projects
3 participants