Conversation
ActuallyTaylor
left a comment
There was a problem hiding this comment.
I have quite a few comments, my main note is that the PR needs to use more EVT-Core abstractions. There is a re-implementation of GPIO handling, which is already covered by our GPIO class. If it is not completely covered, the GPIO class should be subclassed and adapted.
| typedef struct { | ||
| uint16_t PIN; | ||
| GPIO_TypeDef* PORT; | ||
| } GPIO; |
There was a problem hiding this comment.
EVT Core has a GPIO implementation already... We should always stray away from re-defining hardware abstraction since many edge cases and behaviors are handled in our existing abstractions.
https://github.com/RIT-EVT/EVT-core/blob/main/include/core/io/GPIO.hpp
There was a problem hiding this comment.
This is directly taken from the STM32 Cube HUDL project's FMC I am working. It can definitely be removed without causing conflicts
| struct SdramInitConfig { | ||
| FMC_SDRAM_TypeDef* sdramDevice = FMC_SDRAM_DEVICE; | ||
| uint32_t sdBank = FMC_SDRAM_BANK1; | ||
| uint32_t columnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8; | ||
| uint32_t rowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; | ||
| uint32_t memoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16; | ||
| uint32_t internalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; | ||
| uint32_t casLatency = FMC_SDRAM_CAS_LATENCY_2; | ||
| uint32_t writeProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; | ||
| uint32_t sdClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2; | ||
| uint32_t readBurst = FMC_SDRAM_RBURST_ENABLE; | ||
| uint32_t readPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; | ||
| }; |
There was a problem hiding this comment.
These structures are not going to be unique for the F4. They should be a part of the core FMC class. Initialization of the values can happen within the FMCf4xx.hpp but the struct definition should happen in the main FMC.hpp
There was a problem hiding this comment.
These also might change based on what RAM on what platform we are targeting. This was generated by CubeMX, so it might be worthwhile to make this a passed in struct
There was a problem hiding this comment.
Got it, the sdramDevice is a HAL specific macro but that can be separated from the init config so that the config can be defined in the base FMC.hpp.
| /** | ||
| * Structure to simplify SDRAM timing initialization, pre-filled with default values | ||
| * | ||
| * Contains all required SDRAM timing delays in clock cycles. | ||
| */ | ||
| struct SdramTimingConfig { | ||
| uint32_t loadToActiveDelay = LOAD_MODE_REGISTER_TO_ACTIVE; | ||
| uint32_t exitSelfRefreshDelay = EXIT_SELF_REFRESH_DELAY; | ||
| uint32_t selfRefreshTime = SELF_REFRESH_TIME; | ||
| uint32_t rowCycleDelay = ROW_CYCLE_DELAY; | ||
| uint32_t writeRecoveryTime = RECOVERY_DELAY; | ||
| uint32_t rpDelay = ROW_PRECHARGE_DELAY; | ||
| uint32_t rcdDelay = ROW_TO_COLUMN_DELAY; | ||
| }; |
There was a problem hiding this comment.
This should also be located within the FMC base class.
| void FMCf4xx::write32(uint32_t offset, uint32_t value) const { | ||
| // Ensure 4-byte alignment | ||
| if (offset % sizeof(uint32_t) != 0) | ||
| return; | ||
|
|
||
| // Ensure within SDRAM bounds | ||
| if (offset >= RAM_SIZE) | ||
| return; | ||
|
|
||
| auto* const ptr = reinterpret_cast<volatile uint32_t*>(sdramMemoryAddress + offset); | ||
|
|
||
| *ptr = value; | ||
| } |
There was a problem hiding this comment.
This should return a STATUS enumeration that will tell someone if it succeeded or not.
There was a problem hiding this comment.
This method should not exist
| uint32_t FMCf4xx::read32(uint32_t offset) const { | ||
| // Ensure 4-byte alignment | ||
| if (offset % sizeof(uint32_t) != 0) | ||
| return 0; | ||
|
|
||
| // Ensure within SDRAM bounds | ||
| if (offset >= RAM_SIZE) | ||
| return 0; | ||
|
|
||
| auto* const ptr = reinterpret_cast<volatile uint32_t*>(sdramMemoryAddress + offset); | ||
|
|
||
| return *ptr; | ||
| } |
There was a problem hiding this comment.
This should return a STATUS enumeration that will tell a user if it was able to read or not. The value should be passed back through a pointer in the function parameters. See how we do this in the BMS: https://github.com/RIT-EVT/BMS/blob/00bc33d695f8865c8ae2ff0de5e493eb70ec08ca/src/dev/BQ76952.cpp#L241
There was a problem hiding this comment.
This method should not exist either
src/core/io/FMC.cpp
Outdated
| FMC::FMC(uint32_t sdramMemoryAddress) { | ||
| this->sdramMemoryAddress = sdramMemoryAddress; | ||
| } |
There was a problem hiding this comment.
This should be using constructor initialization. An example of this in EVT-Core: https://github.com/RIT-EVT/EVT-core/blob/main/src/core/io/ADC.cpp
There was a problem hiding this comment.
I have a couple file wide notes.
- Existing EVT-Core abstractions should be used. The code is using a custom GPIO implementation which is more work than necessary as well as duplicating existing code.
- All pins in this file should use the EVT-Core pin class
src/core/io/FMC.cpp
Outdated
| @@ -0,0 +1,9 @@ | |||
| #include "core/io/FMC.hpp" | |||
There was a problem hiding this comment.
This should use angled bracket inclusion <>
| #include "HALf4/stm32f4xx_hal.h" | ||
| #include "HALf4/stm32f4xx_hal_sdram.h" | ||
| #include "HALf4/stm32f4xx_ll_fmc.h" | ||
|
|
||
| #include "core/io/FMC.hpp" |
There was a problem hiding this comment.
This should use angled bracket inclusion <>
| * - SDRAM timing configuration | ||
| * - SDRAM read/write operations | ||
| * | ||
| * @note Requires STM32 HAL libraries. |
There was a problem hiding this comment.
All of our platforms require STM32 HAL libraries, so this comment is not really applicable.
| #define FMC_SDNWE ((FMC_CMD){GPIO_PIN_5, GPIOH}) | ||
| #define FMC_SDNRAS ((FMC_CMD){GPIO_PIN_11, GPIOF}) | ||
|
|
||
| // #define FMC_ ((GPIO) {GPIO_PIN_x, GPIOx}) |
There was a problem hiding this comment.
All the above defines can definitely be removed for the future. They did not prove helpful in the HUDL project, and only add to confusion
| #define LOAD_MODE_REGISTER_TO_ACTIVE (NS_TO_SDRAM_CLK_CYCLES(tMRD)) | ||
|
|
||
| #define RAM_SIZE (0x4000000) // 64 megabits | ||
| #define STARTING_ADDR ((uint32_t*) 0xC000000) |
There was a problem hiding this comment.
There are some additional defines in the HUDL project that could prove useful, but I am wondering if we can simply turn these into functions that get executed on construction of the object.
In any case, a method to simply find the clock speed of the FMC could be helpful, and at that point just make everything happen at runtime. No preprocessing magic
| FMC_BANK* pins; | ||
| uint8_t count; | ||
| }; | ||
|
|
There was a problem hiding this comment.
Change these to be wrappers of the evt core GPIO pins instead of the above macros
|
|
||
| void write32(uint32_t offset, uint32_t value) const; | ||
|
|
||
| uint32_t read32(uint32_t offset) const; |
There was a problem hiding this comment.
These should not be explicitly be defined. If you try to write or read from a value at the address of FMC Bank (the STARTING_ADDRESS macro), then it should simply work with some hardware magic from the peripheral
include/core/io/FMC.hpp
Outdated
| * @param[in] offset Byte offset from the SDRAM base address | ||
| */ | ||
| uint32_t read32(uint32_t offset) const; | ||
|
|
There was a problem hiding this comment.
Reading or writing data of any size to the address of the FMC will cause reads and writes to the underlying RAM
include/core/io/FMC.hpp
Outdated
| uint32_t read32(uint32_t offset) const; | ||
|
|
||
| protected: | ||
| uint32_t sdramMemoryAddress; |
There was a problem hiding this comment.
should be a void pointer to signify that it is a memory address. That's what you would do in C, but maybe there is some other convention for C++
There was a problem hiding this comment.
Do I still need this if im removing the read and write functions?
include/core/io/FMC.hpp
Outdated
|
|
||
| protected: | ||
| uint32_t sdramMemoryAddress; | ||
| }; |
There was a problem hiding this comment.
The public section of this should also include wrappers for the methods that can be seen in stm32f4xx_ll_fmc.h. Namely, FMC_SDRAM_WriteProtection_Enable and FMC_SDRAM_WriteProtection_Disable. I have not checked if those are available on the F3, but I would be shocked if they weren't
There was a problem hiding this comment.
The F3 FMC doesn't seem to support any SDRAM operations at all
…to use EVT-core's gpio abstraction
… the base class and finally figured out how GPIO works
…into feature/ChongOscar/fmc-support # Conflicts: # include/core/io/FMC.hpp # include/core/io/platform/f4xx/FMCf4xx.hpp # src/core/io/platform/f4xx/FMCf4xx.cpp
…into feature/ChongOscar/fmc-support # Conflicts: # include/core/io/FMC.hpp # include/core/io/platform/f4xx/FMCf4xx.hpp # src/core/io/FMC.cpp # src/core/io/platform/f4xx/FMCf4xx.cpp
…into feature/ChongOscar/fmc-support # Conflicts: # src/core/io/platform/f4xx/FMCf4xx.cpp
FMC support
Added support for configuring and reading SDRAM through a Flexible Memory Controller (FMC)
Change list:
FMC: is an abstract class containing only the base address for future chip supportFMCf4xx: defines a FMC implementation for F4 boards