├── .github ├── bors.toml └── workflows │ ├── ci.yml │ └── rustfmt.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── rustfmt.toml ├── src ├── devices │ ├── README.md │ ├── as4c16m32msa.rs │ ├── as4c4m16sa.rs │ ├── is42s16400j.rs │ ├── is42s32400f.rs │ ├── is42s32800g.rs │ ├── mod.rs │ ├── mt48lc4m32b2.rs │ └── s34ml08g3.rs ├── fmc.rs ├── lib.rs ├── macros.rs ├── nand.rs ├── nand │ └── device.rs ├── ral │ ├── mod.rs │ ├── peripherals │ │ ├── fmc.rs │ │ └── mod.rs │ └── register.rs └── sdram.rs └── tests ├── dummy_pins.rs └── sdram_pin.rs /.github/bors.toml: -------------------------------------------------------------------------------- 1 | status = [ 2 | "build-dev (1.43.0)", 3 | "build-dev (stable)", 4 | ] 5 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | 3 | on: 4 | push: 5 | branches: [ staging, trying, master ] 6 | pull_request: 7 | 8 | jobs: 9 | build-dev: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | rust: 14 | - 1.43.0 # MSRV 15 | - stable 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - uses: actions-rs/toolchain@v1 20 | with: 21 | profile: minimal 22 | toolchain: ${{ matrix.rust }} 23 | 24 | - name: Build 25 | run: | 26 | cargo test --verbose --features=sdram,nand 27 | -------------------------------------------------------------------------------- /.github/workflows/rustfmt.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [ staging, trying, master ] 4 | pull_request: 5 | 6 | name: Code formatting check 7 | 8 | jobs: 9 | fmt: 10 | name: Rustfmt 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions-rs/toolchain@v1 15 | with: 16 | profile: minimal 17 | toolchain: stable 18 | override: true 19 | - run: rustup component add rustfmt 20 | - uses: actions-rs/cargo@v1 21 | with: 22 | command: fmt 23 | args: --all -- --check 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gdbinit 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | *.hex 6 | *.bin 7 | .gdb_history -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [Unreleased] 4 | 5 | ## [v0.4.0] 2024-12-30 6 | 7 | * Upgrade to embedded-hal v1.0 [#13] 8 | 9 | ## [v0.3.2] 2024-08-04 10 | 11 | * Fix: Add import for IS42S32400F 12 | 13 | ## [v0.3.1] 2024-08-04 14 | 15 | * Add IS42S32400F to devices [#14] 16 | 17 | ## [v0.3.0] 2022-12-29 18 | 19 | * Parallel NAND Flash is supported with the `nand ` feature flag [#9] 20 | * Add S34ML08G3 NAND [#8] 21 | * Add support for defmt logging. Add support for dumping register contents at the end of init function. [#7] 22 | 23 | ## [v0.2.4] 2021-10-05 24 | 25 | * Add AS4C4M16SA-6 device [#5] 26 | 27 | ## [v0.2.3] 2021-05-25 28 | 29 | * Fix the number of columns for the MT48LC4M32B2 device [#4] 30 | 31 | ## [v0.2.2] 2021-03-27 32 | 33 | * Implement AS4C16M32MSA-6BIN device [#3] 34 | 35 | ## [v0.2.1] 2020-11-07 36 | 37 | * Export SdramConfiguration and SdramTiming structs to fix implementing 38 | SdramChip outside the crate https://github.com/stm32-rs/stm32-fmc/pull/2 39 | 40 | ## [v0.2.0] 2020-08-28 41 | 42 | * *Breaking*: Use a generic type to support pin checking on SDRAMs with 11 and 43 | 13 address lines. `PinsSdram` now has two generic types. 44 | 45 | ## [v0.1.2] 2020-08-05 46 | 47 | * Don't require type to be `Sync` in order to implement FmcPeripheral 48 | * Begin Changelog 49 | 50 | [Unreleased]: https://github.com/stm32-rs/stm32-fmc/compare/v0.4.0...HEAD 51 | [v0.3.2]: https://github.com/stm32-rs/stm32-fmc/compare/v0.3.2...v0.4.0 52 | [v0.3.2]: https://github.com/stm32-rs/stm32-fmc/compare/v0.3.1...v0.3.2 53 | [v0.3.1]: https://github.com/stm32-rs/stm32-fmc/compare/v0.3.0...v0.3.1 54 | [v0.3.0]: https://github.com/stm32-rs/stm32-fmc/compare/v0.2.4...v0.3.0 55 | [v0.2.4]: https://github.com/stm32-rs/stm32-fmc/compare/v0.2.3...v0.2.4 56 | [v0.2.3]: https://github.com/stm32-rs/stm32-fmc/compare/v0.2.2...v0.2.3 57 | [v0.2.2]: https://github.com/stm32-rs/stm32-fmc/compare/v0.2.1...v0.2.2 58 | [v0.2.1]: https://github.com/stm32-rs/stm32-fmc/compare/v0.2.0...v0.2.1 59 | [v0.2.0]: https://github.com/stm32-rs/stm32-fmc/compare/v0.1.2...v0.2.0 60 | 61 | [#3]: https://github.com/stm32-rs/stm32-fmc/pull/3 62 | [#4]: https://github.com/stm32-rs/stm32-fmc/pull/4 63 | [#5]: https://github.com/stm32-rs/stm32-fmc/pull/5 64 | [#7]: https://github.com/stm32-rs/stm32-fmc/pull/7 65 | [#8]: https://github.com/stm32-rs/stm32-fmc/pull/8 66 | [#9]: https://github.com/stm32-rs/stm32-fmc/pull/9 67 | [#13]: https://github.com/stm32-rs/stm32-fmc/pull/13 68 | [#14]: https://github.com/stm32-rs/stm32-fmc/pull/14 69 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stm32-fmc" 3 | version = "0.4.0" 4 | authors = ["Richard Meadows "] 5 | edition = "2018" 6 | categories = ["embedded", "hardware-support", "no-std"] 7 | description = "Hardware Abstraction Layer for STM32 Memory Controllers (FMC/FSMC)" 8 | keywords = ["stm32", "fmc", "sdram", "memory"] 9 | repository = "https://github.com/stm32-rs/stm32-fmc" 10 | license = "MIT/Apache-2.0" 11 | readme = "README.md" 12 | exclude = [".gitignore"] 13 | 14 | [package.metadata.docs.rs] 15 | features = ["sdram", "nand"] 16 | 17 | [dependencies.log] 18 | version = "^0.4.8" 19 | default-features = false 20 | optional = true 21 | 22 | [dependencies.defmt] 23 | version = "0.3" 24 | optional = true 25 | 26 | [dependencies] 27 | embedded-hal = { version = "1.0" } 28 | 29 | [dev-dependencies] 30 | paste = "1.0" 31 | 32 | [features] 33 | trace-register-values = [] 34 | sdram = [] 35 | nand = [] 36 | default = ["sdram", "nand"] 37 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Richard Meadows 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Documentation](https://docs.rs/stm32-fmc) 2 | 3 | # stm32-fmc 4 | 5 | [![docs.rs](https://docs.rs/stm32-fmc/badge.svg)](https://docs.rs/stm32-fmc) 6 | [![Crates.io](https://img.shields.io/crates/v/stm32-fmc.svg)](https://crates.io/crates/stm32-fmc) 7 | 8 | Hardware Abstraction Layer for STM32 Memory Controllers (FMC/FSMC) 9 | 10 | Currently only SDRAM functions are implemented. 11 | 12 | **This crate is a work in progress! Contributions very welcome** 13 | 14 | ## Implementing 15 | 16 | (If your HAL already implements FMC, you can skip this) 17 | 18 | See the [docs](https://docs.rs/stm32-fmc) 19 | 20 | # Usage 21 | 22 | ### SDRAM 23 | 24 | The FMC peripheral supports up to 2 external SDRAM devices. This crate currently 25 | only supports 1, although it may be on either bank 1 or 2. 26 | 27 | External memories are defined by 28 | [`SdramChip`](https://docs.rs/stm32-fmc/latest/stm32_fmc/trait.SdramChip.html) 29 | implementations. There are several examples in the [`devices`](src/devices/) 30 | folder, or you can make your own. 31 | 32 | To pass pins to a constructor, create a tuple with the following ordering: 33 | 34 | ```rust 35 | let pins = ( 36 | // A0-A12 37 | pa0, ... 38 | // BA0-BA1 39 | // D0-D31 40 | // NBL0 - NBL3 41 | // SDCKE 42 | // SDCLK 43 | // SDNCAS 44 | // SDNE 45 | // SDRAS 46 | // SDNWE 47 | ); 48 | ``` 49 | 50 | You can leave out address/data pins not used by your memory. 51 | 52 | #### Constructing 53 | 54 | If you are using a HAL, see the HAL documentation. 55 | 56 | Otherwise you can implement 57 | [`FmcPeripheral`](https://docs.rs/stm32-fmc/latest/stm32_fmc/trait.FmcPeripheral.html) 58 | yourself then use 59 | [`Sdram::new`](https://docs.rs/stm32-fmc/latest/stm32_fmc/struct.Sdram.html#method.new) 60 | / 61 | [`Sdram::new_unchecked`](https://docs.rs/stm32-fmc/latest/stm32_fmc/struct.Sdram.html#method.new_unchecked) 62 | directly. 63 | 64 | #### Initialising 65 | 66 | Once you have an 67 | [`Sdram`](https://docs.rs/stm32-fmc/latest/stm32_fmc/struct.Sdram.html) 68 | instance, you can: 69 | 70 | * Initialise it by calling 71 | [`init`](https://docs.rs/stm32-fmc/latest/stm32_fmc/struct.Sdram.html#method.init). This 72 | returns a raw pointer 73 | * Convert the raw pointer to a sized slice using `from_raw_parts_mut` 74 | 75 | ```rust 76 | let ram = unsafe { 77 | // Initialise controller and SDRAM 78 | let ram_ptr: *mut u32 = sdram.init(&mut delay); 79 | 80 | // 32 MByte = 256Mbit SDRAM = 8M u32 words 81 | slice::from_raw_parts_mut(ram_ptr, 8 * 1024 * 1024) 82 | }; 83 | ``` 84 | 85 | ### NAND Flash 86 | 87 | The FMC peripheral supports once external parallel NAND flash device. 88 | 89 | External memories are defined by 90 | [`NandChip`](https://docs.rs/stm32-fmc/latest/stm32_fmc/trait.NandChip.html) 91 | implementations. There are examples in the [`devices`](src/devices/) folder, or 92 | you can make your own. 93 | 94 | To pass pins to a constructor, create a tuple with the following ordering: 95 | 96 | ```rust 97 | let pins = ( 98 | // A17/ALE 99 | // A16/CLE 100 | pa0, ... 101 | // D0-D7 102 | // NCE/#CE 103 | // NOE/#RE 104 | // NWE/#WE 105 | // NWAIT/R/#B 106 | ); 107 | ``` 108 | 109 | #### Constructing 110 | 111 | If you are using a HAL, see the HAL documentation. 112 | 113 | Otherwise you can implement 114 | [`FmcPeripheral`](https://docs.rs/stm32-fmc/latest/stm32_fmc/trait.FmcPeripheral.html) 115 | yourself then use 116 | [`Nand::new`](https://docs.rs/stm32-fmc/latest/stm32_fmc/struct.Nand.html#method.new) 117 | / 118 | [`Nand::new_unchecked`](https://docs.rs/stm32-fmc/latest/stm32_fmc/struct.Nand.html#method.new_unchecked) 119 | directly. 120 | 121 | #### Initialising 122 | 123 | Once you have an 124 | [`Nand`](https://docs.rs/stm32-fmc/latest/stm32_fmc/struct.Nand.html) instance 125 | you should initialise it by calling 126 | [`init`](https://docs.rs/stm32-fmc/latest/stm32_fmc/struct.Nand.html#method.init). This 127 | returns a 128 | [`NandDevice`](https://docs.rs/stm32-fmc/latest/stm32_fmc/nand_device/struct.NandDevice.html) 129 | instance. 130 | 131 | ```rust 132 | let mut nand_device = nand.init(&mut delay); 133 | 134 | // Read device identifier 135 | let id = nand_device.read_id(); 136 | ``` 137 | 138 | ### NOR Flash/PSRAM 139 | 140 | TODO 141 | 142 | ### Troubleshooting 143 | The library automatically does some trace-level logging either via `log` or via `defmt`. 144 | To enable such logging, enable either the `log` or `defmt` feature in your `Cargo.toml`. 145 | 146 | For debugging the SDRAM register contents, the library provides additional feature `trace-register-values`, which when enabled causes the init function to log the register contents to the trace level. 147 | This is useful for example when you want to compare the register values between `stm32-fmc` and CubeMX code. 148 | Note that one of the logging features (`log`/`defmt`) must be enabled for this to work. 149 | 150 | ### Implementing a new device 151 | 152 | If you end up depending on a fork or a newer version of this crate than the 153 | HAL crate for your device, you can override the version pulled in by the 154 | external crate using a `[patch]` section in your `Cargo.toml`, as described 155 | in the 156 | [Cargo Book](https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html#the-patch-section). 157 | 158 | ## Releasing 159 | 160 | * Update Cargo.toml 161 | * Update CHANGELOG.md 162 | 163 | ``` 164 | git commit -am 'v0.2.0' 165 | git push --set-upstream origin v0.2.0 166 | ``` 167 | 168 | Create a PR and check CI passes 169 | 170 | ``` 171 | git push --set-upstream origin v0.2.0:master 172 | git tag -a 'v0.2.0' -m 'v0.2.0' 173 | git push origin refs/tags/v0.2.0 174 | cargo publish 175 | ``` 176 | 177 | ## License 178 | 179 | Licensed under either of 180 | 181 | * Apache License, Version 2.0 182 | ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 183 | * MIT license 184 | ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 185 | 186 | at your option. 187 | 188 | ## Contribution 189 | 190 | Unless you explicitly state otherwise, any contribution intentionally submitted 191 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 192 | dual licensed as above, without any additional terms or conditions. 193 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # r u s t f m t - C O N F I G 3 | # ======================================================================== 4 | # Maximum width of each line. 5 | max_width = 80 6 | # Number of spaces per tab. 7 | tab_spaces = 4 8 | 9 | newline_style = "Unix" -------------------------------------------------------------------------------- /src/devices/README.md: -------------------------------------------------------------------------------- 1 | # Memory device definitions 2 | -------------------------------------------------------------------------------- /src/devices/as4c16m32msa.rs: -------------------------------------------------------------------------------- 1 | /// Alliance Memory AS4C16M32MSA SDRAM 2 | #[allow(unused)] 3 | 4 | pub mod as4c16m32msa_6 { 5 | use crate::sdram::{SdramChip, SdramConfiguration, SdramTiming}; 6 | 7 | const BURST_LENGTH_1: u16 = 0x0000; 8 | const BURST_LENGTH_2: u16 = 0x0001; 9 | const BURST_LENGTH_4: u16 = 0x0002; 10 | const BURST_LENGTH_8: u16 = 0x0004; 11 | const BURST_TYPE_SEQUENTIAL: u16 = 0x0000; 12 | const BURST_TYPE_INTERLEAVED: u16 = 0x0008; 13 | const CAS_LATENCY_1: u16 = 0x0010; 14 | const CAS_LATENCY_2: u16 = 0x0020; 15 | const CAS_LATENCY_3: u16 = 0x0030; 16 | const OPERATING_MODE_STANDARD: u16 = 0x0000; 17 | const WRITEBURST_MODE_PROGRAMMED: u16 = 0x0000; 18 | const WRITEBURST_MODE_SINGLE: u16 = 0x0200; 19 | 20 | /// As4c16m32msa 21 | #[derive(Clone, Copy, Debug, PartialEq)] 22 | pub struct As4c16m32msa {} 23 | 24 | impl SdramChip for As4c16m32msa { 25 | /// Value of the mode register 26 | const MODE_REGISTER: u16 = BURST_LENGTH_1 27 | | BURST_TYPE_SEQUENTIAL 28 | | CAS_LATENCY_3 29 | | OPERATING_MODE_STANDARD 30 | | WRITEBURST_MODE_SINGLE; 31 | 32 | // 166MHz = 6.024ns per clock cycle 33 | 34 | /// Timing Parameters 35 | const TIMING: SdramTiming = SdramTiming { 36 | startup_delay_ns: 200_000, // 200 µs 37 | max_sd_clock_hz: 166_000_000, // 166 MHz 38 | refresh_period_ns: 7_813, // 64ms / (8192 rows) = 7812.5ns 39 | mode_register_to_active: 2, // tMRD = 2 cycles 40 | exit_self_refresh: 14, // tXSR = 80ns 41 | active_to_precharge: 8, // tRAS = 48ns 42 | row_cycle: 10, // tRC = 60ns 43 | row_precharge: 3, // tRP = 18ns 44 | row_to_column: 3, // tRCD = 18ns 45 | }; 46 | 47 | /// SDRAM controller configuration 48 | const CONFIG: SdramConfiguration = SdramConfiguration { 49 | column_bits: 9, // A0-A8 50 | row_bits: 13, // A0-A12 51 | memory_data_width: 32, // 32-bit 52 | internal_banks: 4, // 4 internal banks 53 | cas_latency: 3, // CAS latency = 3 54 | write_protection: false, 55 | read_burst: true, 56 | read_pipe_delay_cycles: 0, 57 | }; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/devices/as4c4m16sa.rs: -------------------------------------------------------------------------------- 1 | /// Alliance Memory AS4C4M16SA SDRAM 2 | /// 3 | #[allow(unused)] 4 | 5 | pub mod as4c4m16sa_6 { 6 | use crate::sdram::{SdramChip, SdramConfiguration, SdramTiming}; 7 | 8 | // Burst length 9 | const BURST_LENGTH_1: u16 = 0b0000_0000_0000_0000; // A2 = 0, A1 = 0, A0 = 0 10 | const BURST_LENGTH_2: u16 = 0b0000_0000_0000_0001; // A2 = 0, A1 = 0, A0 = 1 11 | const BURST_LENGTH_4: u16 = 0b0000_0000_0000_0010; // A2 = 0, A1 = 1, A0 = 0 12 | const BURST_LENGTH_8: u16 = 0b0000_0000_0000_0011; // A2 = 0, A1 = 1, A0 = 1 13 | const BURST_LENGTH_FULL_PAGE_SEQUENTIAL: u16 = 0b0000_0000_0000_0111; // A2 = 1, A1 = 1, A0 = 1 14 | 15 | // Burst type 16 | const BURST_TYPE_SEQUENTIAL: u16 = 0b0000_0000_0000_0000; // A3 = 0 17 | const BURST_TYPE_INTERLEAVED: u16 = 0b0000_0000_0000_1000; // A3 = 1 18 | 19 | // CAS Latency 20 | const CAS_LATENCY_2: u16 = 0b0000_0000_0010_0000; // A6 = 0, A5 = 1, A4 = 0 21 | const CAS_LATENCY_3: u16 = 0b0000_0000_0011_0000; // A6 = 0, A5 = 1, A4 = 1 22 | 23 | // Test mode 24 | const TEST_MODE_NORMAL: u16 = 0b0000_0000_0000_0000; // A8 = 0, A7 = 0 25 | const TEST_MODE_VENDOR_USE_ONLY_10: u16 = 0b0000_0001_0000_0000; // A8 = 1, A7 = 0 26 | const TEST_MODE_VENDOR_USE_ONLY_01: u16 = 0b0000_0000_1000_0000; // A8 = 0, A7 = 1 27 | 28 | // Write burst length 29 | const WRITE_BURST_LENGTH_BURST: u16 = 0b0000_0000_0000_0000; // A9 = 0 30 | const WRITE_BURST_LENGTH_SINGLE_BIT: u16 = 0b0000_0010_0000_0000; // A9 = 1 31 | 32 | // RFU* = 0 33 | 34 | /// As4c4m16sa 35 | #[derive(Clone, Copy, Debug, PartialEq)] 36 | pub struct As4c4m16sa {} 37 | 38 | impl SdramChip for As4c4m16sa { 39 | /// Value of the mode register 40 | const MODE_REGISTER: u16 = BURST_LENGTH_1 41 | | BURST_TYPE_SEQUENTIAL 42 | | CAS_LATENCY_3 43 | | TEST_MODE_NORMAL 44 | | WRITE_BURST_LENGTH_SINGLE_BIT; 45 | 46 | // 166MHz = 6.024ns per clock cycle 47 | 48 | /// Timing Parameters 49 | const TIMING: SdramTiming = SdramTiming { 50 | startup_delay_ns: 200_000, // 200 µs 51 | max_sd_clock_hz: 166_000_000, // 166 MHz 52 | refresh_period_ns: 15_625, // 64ms / (4096 rows) = 15625ns 53 | mode_register_to_active: 2, // tMRD = 2 cycles 54 | exit_self_refresh: 11, // tXSR = 62ns, cycles = ceil(166000000*(62*10^(-9))) 55 | active_to_precharge: 7, // tRAS = 42ns cycles = ceil(166000000*(42*10^(-9))) 56 | row_cycle: 10, // tRC = 60ns cycles = ceil(166000000*(60*10^(-9))) 57 | row_precharge: 3, // tRP = 18ns cycles = ceil(166000000*(18*10^(-9))) 58 | row_to_column: 3, // tRCD = 18ns cycles = ceil(166000000*(18*10^(-9))) 59 | }; 60 | 61 | /// SDRAM controller configuration 62 | const CONFIG: SdramConfiguration = SdramConfiguration { 63 | column_bits: 8, // A0-A7 64 | row_bits: 13, // A0-A12 65 | memory_data_width: 16, // 16-bit 66 | internal_banks: 4, // 4 internal banks 67 | cas_latency: 3, // CAS latency = 3 68 | write_protection: false, 69 | read_burst: true, 70 | read_pipe_delay_cycles: 0, 71 | }; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/devices/is42s16400j.rs: -------------------------------------------------------------------------------- 1 | /// ISI IS42S16400J SDRAM 2 | #[allow(unused)] 3 | 4 | /// Speed Grade 7 5 | pub mod is42s16400j_7 { 6 | use crate::sdram::{SdramChip, SdramConfiguration, SdramTiming}; 7 | 8 | const BURST_LENGTH_1: u16 = 0x0000; 9 | const BURST_LENGTH_2: u16 = 0x0001; 10 | const BURST_LENGTH_4: u16 = 0x0002; 11 | const BURST_LENGTH_8: u16 = 0x0004; 12 | const BURST_TYPE_SEQUENTIAL: u16 = 0x0000; 13 | const BURST_TYPE_INTERLEAVED: u16 = 0x0008; 14 | const CAS_LATENCY_2: u16 = 0x0020; 15 | const CAS_LATENCY_3: u16 = 0x0030; 16 | const OPERATING_MODE_STANDARD: u16 = 0x0000; 17 | const WRITEBURST_MODE_PROGRAMMED: u16 = 0x0000; 18 | const WRITEBURST_MODE_SINGLE: u16 = 0x0200; 19 | 20 | /// Is42s16400j with Speed Grade 7 21 | /// 22 | /// Configured with CAS latency 2, limited 100MHz 23 | #[derive(Clone, Copy, Debug, PartialEq)] 24 | pub struct Is42s16400j {} 25 | 26 | impl SdramChip for Is42s16400j { 27 | /// Value of the mode register 28 | const MODE_REGISTER: u16 = BURST_LENGTH_1 29 | | BURST_TYPE_SEQUENTIAL 30 | | CAS_LATENCY_2 31 | | OPERATING_MODE_STANDARD 32 | | WRITEBURST_MODE_SINGLE; 33 | 34 | /// Timing Parameters 35 | const TIMING: SdramTiming = SdramTiming { 36 | startup_delay_ns: 100_000, // 100 µs 37 | max_sd_clock_hz: 100_000_000, // 100 MHz 38 | refresh_period_ns: 15_625, // 64ms / (4096 rows) = 15625ns 39 | mode_register_to_active: 2, // tMRD = 2 cycles 40 | exit_self_refresh: 7, // tXSR = 70ns 41 | active_to_precharge: 4, // tRAS = 42ns 42 | row_cycle: 7, // tRC = 63ns 43 | row_precharge: 2, // tRP = 15ns 44 | row_to_column: 2, // tRCD = 15ns 45 | }; 46 | 47 | /// SDRAM controller configuration 48 | const CONFIG: SdramConfiguration = SdramConfiguration { 49 | column_bits: 8, 50 | row_bits: 12, 51 | memory_data_width: 16, // 16-bit 52 | internal_banks: 4, // 4 internal banks 53 | cas_latency: 2, // CAS latency = 2 54 | write_protection: false, 55 | read_burst: true, 56 | read_pipe_delay_cycles: 0, 57 | }; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/devices/is42s32400f.rs: -------------------------------------------------------------------------------- 1 | /// ISI IS42S32400F SDRAM 2 | #[allow(unused)] 3 | 4 | /// Speed Grade 6 5 | pub mod is42s32400f_6 { 6 | use crate::sdram::{SdramChip, SdramConfiguration, SdramTiming}; 7 | 8 | const BURST_LENGTH_1: u16 = 0x0000; 9 | const BURST_LENGTH_2: u16 = 0x0001; 10 | const BURST_LENGTH_4: u16 = 0x0002; 11 | const BURST_LENGTH_8: u16 = 0x0004; 12 | const BURST_TYPE_SEQUENTIAL: u16 = 0x0000; 13 | const BURST_TYPE_INTERLEAVED: u16 = 0x0008; 14 | const CAS_LATENCY_2: u16 = 0x0020; 15 | const CAS_LATENCY_3: u16 = 0x0030; 16 | const OPERATING_MODE_STANDARD: u16 = 0x0000; 17 | const WRITEBURST_MODE_PROGRAMMED: u16 = 0x0000; 18 | const WRITEBURST_MODE_SINGLE: u16 = 0x0200; 19 | 20 | /// Is42s32400f with Speed Grade 6 21 | #[derive(Clone, Copy, Debug, PartialEq)] 22 | pub struct Is42s32400f6 {} 23 | 24 | impl SdramChip for Is42s32400f6 { 25 | /// Value of the mode register 26 | const MODE_REGISTER: u16 = BURST_LENGTH_1 27 | | BURST_TYPE_SEQUENTIAL 28 | | CAS_LATENCY_3 29 | | OPERATING_MODE_STANDARD 30 | | WRITEBURST_MODE_SINGLE; 31 | 32 | /// Timing Parameters 33 | const TIMING: SdramTiming = SdramTiming { 34 | startup_delay_ns: 100_000, // 100 µs 35 | max_sd_clock_hz: 100_000_000, // 100 MHz 36 | refresh_period_ns: 15_625, // 64ms / (4096 rows) = 15625ns 37 | mode_register_to_active: 2, // tMRD = 2 cycles 38 | exit_self_refresh: 7, // tXSR = 70ns 39 | active_to_precharge: 4, // tRAS = 42ns 40 | row_cycle: 6, // tRC = 60ns 41 | row_precharge: 2, // tRP = 18ns 42 | row_to_column: 2, // tRCD = 18ns 43 | }; 44 | 45 | /// SDRAM controller configuration 46 | const CONFIG: SdramConfiguration = SdramConfiguration { 47 | column_bits: 8, 48 | row_bits: 12, 49 | memory_data_width: 32, // 32-bit 50 | internal_banks: 4, // 4 internal banks 51 | cas_latency: 3, // CAS latency = 3 52 | write_protection: false, 53 | read_burst: true, 54 | read_pipe_delay_cycles: 0, 55 | }; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/devices/is42s32800g.rs: -------------------------------------------------------------------------------- 1 | /// ISI IS42S32800G SDRAM 2 | #[allow(unused)] 3 | 4 | /// Speed Grade 6 5 | pub mod is42s32800g_6 { 6 | use crate::sdram::{SdramChip, SdramConfiguration, SdramTiming}; 7 | 8 | const BURST_LENGTH_1: u16 = 0x0000; 9 | const BURST_LENGTH_2: u16 = 0x0001; 10 | const BURST_LENGTH_4: u16 = 0x0002; 11 | const BURST_LENGTH_8: u16 = 0x0004; 12 | const BURST_TYPE_SEQUENTIAL: u16 = 0x0000; 13 | const BURST_TYPE_INTERLEAVED: u16 = 0x0008; 14 | const CAS_LATENCY_2: u16 = 0x0020; 15 | const CAS_LATENCY_3: u16 = 0x0030; 16 | const OPERATING_MODE_STANDARD: u16 = 0x0000; 17 | const WRITEBURST_MODE_PROGRAMMED: u16 = 0x0000; 18 | const WRITEBURST_MODE_SINGLE: u16 = 0x0200; 19 | 20 | /// Is42s32800g with Speed Grade 6 21 | #[derive(Clone, Copy, Debug, PartialEq)] 22 | pub struct Is42s32800g {} 23 | 24 | impl SdramChip for Is42s32800g { 25 | /// Value of the mode register 26 | const MODE_REGISTER: u16 = BURST_LENGTH_1 27 | | BURST_TYPE_SEQUENTIAL 28 | | CAS_LATENCY_3 29 | | OPERATING_MODE_STANDARD 30 | | WRITEBURST_MODE_SINGLE; 31 | 32 | /// Timing Parameters 33 | const TIMING: SdramTiming = SdramTiming { 34 | startup_delay_ns: 100_000, // 100 µs 35 | max_sd_clock_hz: 100_000_000, // 100 MHz 36 | refresh_period_ns: 15_625, // 64ms / (4096 rows) = 15625ns 37 | mode_register_to_active: 2, // tMRD = 2 cycles 38 | exit_self_refresh: 7, // tXSR = 70ns 39 | active_to_precharge: 4, // tRAS = 42ns 40 | row_cycle: 7, // tRC = 70ns 41 | row_precharge: 2, // tRP = 18ns 42 | row_to_column: 2, // tRCD = 18ns 43 | }; 44 | 45 | /// SDRAM controller configuration 46 | const CONFIG: SdramConfiguration = SdramConfiguration { 47 | column_bits: 9, 48 | row_bits: 12, 49 | memory_data_width: 32, // 32-bit 50 | internal_banks: 4, // 4 internal banks 51 | cas_latency: 3, // CAS latency = 3 52 | write_protection: false, 53 | read_burst: true, 54 | read_pipe_delay_cycles: 0, 55 | }; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/devices/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(missing_docs)] 2 | 3 | #[cfg(feature = "sdram")] 4 | mod as4c4m16sa; 5 | #[cfg(feature = "sdram")] 6 | pub use as4c4m16sa::*; 7 | 8 | #[cfg(feature = "sdram")] 9 | mod as4c16m32msa; 10 | #[cfg(feature = "sdram")] 11 | pub use as4c16m32msa::*; 12 | 13 | #[cfg(feature = "sdram")] 14 | mod is42s16400j; 15 | #[cfg(feature = "sdram")] 16 | pub use is42s16400j::*; 17 | 18 | #[cfg(feature = "sdram")] 19 | mod is42s32400f; 20 | #[cfg(feature = "sdram")] 21 | pub use is42s32400f::*; 22 | 23 | #[cfg(feature = "sdram")] 24 | mod is42s32800g; 25 | #[cfg(feature = "sdram")] 26 | pub use is42s32800g::*; 27 | 28 | #[cfg(feature = "sdram")] 29 | mod mt48lc4m32b2; 30 | #[cfg(feature = "sdram")] 31 | pub use mt48lc4m32b2::*; 32 | 33 | #[cfg(feature = "nand")] 34 | mod s34ml08g3; 35 | #[cfg(feature = "nand")] 36 | pub use s34ml08g3::*; 37 | -------------------------------------------------------------------------------- /src/devices/mt48lc4m32b2.rs: -------------------------------------------------------------------------------- 1 | /// Micron MT48LC4M32B2 SDRAM 2 | #[allow(unused)] 3 | 4 | /// Speed Grade 6 5 | pub mod mt48lc4m32b2_6 { 6 | use crate::sdram::{SdramChip, SdramConfiguration, SdramTiming}; 7 | 8 | const BURST_LENGTH_1: u16 = 0x0000; 9 | const BURST_LENGTH_2: u16 = 0x0001; 10 | const BURST_LENGTH_4: u16 = 0x0002; 11 | const BURST_LENGTH_8: u16 = 0x0004; 12 | const BURST_TYPE_SEQUENTIAL: u16 = 0x0000; 13 | const BURST_TYPE_INTERLEAVED: u16 = 0x0008; 14 | const CAS_LATENCY_2: u16 = 0x0020; 15 | const CAS_LATENCY_3: u16 = 0x0030; 16 | const OPERATING_MODE_STANDARD: u16 = 0x0000; 17 | const WRITEBURST_MODE_PROGRAMMED: u16 = 0x0000; 18 | const WRITEBURST_MODE_SINGLE: u16 = 0x0200; 19 | 20 | /// MT48LC4M32B2 with Speed Grade 6 21 | #[derive(Clone, Copy, Debug, PartialEq)] 22 | pub struct Mt48lc4m32b2 {} 23 | 24 | impl SdramChip for Mt48lc4m32b2 { 25 | /// Value of the mode register 26 | const MODE_REGISTER: u16 = BURST_LENGTH_1 27 | | BURST_TYPE_SEQUENTIAL 28 | | CAS_LATENCY_3 29 | | OPERATING_MODE_STANDARD 30 | | WRITEBURST_MODE_SINGLE; 31 | 32 | /// Timing Parameters 33 | const TIMING: SdramTiming = SdramTiming { 34 | startup_delay_ns: 100_000, // 100 µs 35 | max_sd_clock_hz: 100_000_000, // 100 MHz 36 | refresh_period_ns: 15_625, // 64ms / (4096 rows) = 15625ns 37 | mode_register_to_active: 2, // tMRD = 2 cycles 38 | exit_self_refresh: 7, // tXSR = 70ns 39 | active_to_precharge: 4, // tRAS = 42ns 40 | row_cycle: 7, // tRC = 70ns 41 | row_precharge: 2, // tRP = 18ns 42 | row_to_column: 2, // tRCD = 18ns 43 | }; 44 | 45 | /// SDRAM controller configuration 46 | const CONFIG: SdramConfiguration = SdramConfiguration { 47 | column_bits: 8, 48 | row_bits: 12, 49 | memory_data_width: 32, // 32-bit 50 | internal_banks: 4, // 4 internal banks 51 | cas_latency: 3, // CAS latency = 2 52 | write_protection: false, 53 | read_burst: true, 54 | read_pipe_delay_cycles: 0, 55 | }; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/devices/s34ml08g3.rs: -------------------------------------------------------------------------------- 1 | /// SkyHigh S34ML08G3 SLC NAND Flash 2 | #[allow(unused)] 3 | 4 | /// SkyHigh S34ML08G3 SLC NAND Flash with 4kB pages 5 | pub mod s34ml08g3_4kb { 6 | use crate::nand::{NandChip, NandConfiguration, NandTiming}; 7 | 8 | /// S32ML08G3 9 | #[derive(Clone, Copy, Debug, PartialEq)] 10 | pub struct S34ml08g3 {} 11 | 12 | impl NandChip for S34ml08g3 { 13 | /// Timing Parameters 14 | const TIMING: NandTiming = NandTiming { 15 | nce_setup_time: 15, // tCS = 15ns min 16 | data_setup_time: 7, // tDS = 7ns min 17 | ale_hold_time: 5, // tALH = 5ns min 18 | cle_hold_time: 5, // tCLH = 5ns min 19 | ale_to_nre_delay: 10, // tAR = 10ns min 20 | cle_to_nre_delay: 10, // tCLR = 10ns min 21 | nre_pulse_width_ns: 10, // tRP = 10ns min 22 | nwe_pulse_width_ns: 10, // tWP = 10ns min 23 | read_cycle_time_ns: 20, // tRC = 20ns min 24 | write_cycle_time_ns: 20, // tWC = 20ns min 25 | nwe_high_to_busy_ns: 100, // tWB = 100ns max 26 | }; 27 | 28 | /// Nand controller configuration 29 | const CONFIG: NandConfiguration = NandConfiguration { 30 | data_width: 8, // 8-bit 31 | column_bits: 12, // 4096 byte pages 32 | }; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/fmc.rs: -------------------------------------------------------------------------------- 1 | //! HAL for Flexible memory controller (FMC) 2 | 3 | /// FMC banks 4 | /// 5 | /// For example, see RM0433 rev 7 Figure 98. 6 | #[derive(Clone, Copy, Debug, PartialEq)] 7 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 8 | #[allow(unused)] 9 | pub enum FmcBank { 10 | /// Bank1: NOR/PSRAM/SRAM 11 | Bank1, 12 | /// Bank2: 13 | Bank2, 14 | /// Bank3: NAND Flash 15 | Bank3, 16 | /// Bank4: 17 | Bank4, 18 | /// Bank5: SDRAM 1 19 | Bank5, 20 | /// Bank6: SDRAM 2 21 | Bank6, 22 | } 23 | impl FmcBank { 24 | /// Return a pointer to this FMC bank 25 | pub fn ptr(self) -> *mut u32 { 26 | use FmcBank::*; 27 | (match self { 28 | Bank1 => 0x6000_0000u32, 29 | Bank2 => 0x7000_0000u32, 30 | Bank3 => 0x8000_0000u32, 31 | Bank4 => 0x9000_0000u32, // Not used 32 | Bank5 => 0xC000_0000u32, 33 | Bank6 => 0xD000_0000u32, 34 | }) as *mut u32 35 | } 36 | } 37 | 38 | /// Set of address pins 39 | pub trait AddressPinSet { 40 | /// The number of address pins in this set of pins 41 | const ADDRESS_PINS: u8; 42 | } 43 | 44 | macro_rules! address_pin_markers { 45 | ($($AddressPins:ident, $addr:tt, $doc:expr;)+) => { 46 | $( 47 | /// Type to mark that there are 48 | #[doc=$doc] 49 | /// address pins 50 | #[derive(Clone, Copy, Debug)] 51 | pub struct $AddressPins; 52 | impl AddressPinSet for $AddressPins { 53 | const ADDRESS_PINS: u8 = $addr; 54 | } 55 | )+ 56 | }; 57 | } 58 | address_pin_markers!( 59 | AddressPins11, 11, "11"; 60 | AddressPins12, 12, "12"; 61 | AddressPins13, 13, "13"; 62 | ); 63 | 64 | // ---- SDRAM ---- 65 | 66 | #[cfg(feature = "sdram")] 67 | use crate::sdram::{PinsSdram, SdramBank1, SdramBank2}; 68 | 69 | #[cfg(feature = "sdram")] 70 | macro_rules! impl_16bit_sdram { 71 | ($($pins:tt: [$ckeN:tt, $neN:tt, 72 | $nInternalB:expr 73 | $(, $pba1:ident: $ba1:tt)* ; // BA1 pins 74 | $addressPins:ident 75 | [ $($pa:ident: $a:ident),* ] // Address pins 76 | ]),+) => { 77 | $( 78 | #[rustfmt::skip] 79 | /// 16-bit SDRAM 80 | impl 84 | PinsSdram<$pins, $addressPins> 85 | for (PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8, PA9, PA10, $($pa,)* 86 | PBA0, $($pba1,)* PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, 87 | PD8, PD9, PD10, PD11, PD12, PD13, PD14, PD15, PNBL0, PNBL1, 88 | PSDCKEn, PSDCLK, PSDNCAS, PSDNEn, PSDNRAS, PSDNWE) 89 | where PA0: A0, PA1: A1, PA2: A2, PA3: A3, PA4: A4, PA5: A5, PA6: A6, 90 | PA7: A7, PA8: A8, PA9: A9, PA10: A10, $($pa:$a,)* 91 | PBA0: BA0, $($pba1:$ba1,)* 92 | PD0: D0, PD1: D1, PD2: D2, PD3: D3, PD4: D4, PD5: D5, PD6: D6, 93 | PD7: D7, PD8: D8, PD9: D9, PD10: D10, PD11: D11, PD12: D12, 94 | PD13: D13, PD14: D14, PD15: D15, 95 | PNBL0: NBL0, PNBL1: NBL1, PSDCKEn: $ckeN, PSDCLK: SDCLK, 96 | PSDNCAS: SDNCAS, PSDNEn: $neN, PSDNRAS: SDNRAS, PSDNWE: SDNWE { 97 | 98 | const NUMBER_INTERNAL_BANKS: u8 = $nInternalB; 99 | } 100 | )+ 101 | } 102 | } 103 | 104 | #[cfg(feature = "sdram")] 105 | macro_rules! impl_32bit_sdram { 106 | ($($pins:tt: [$ckeN:tt, $neN:tt, 107 | $nInternalB:expr 108 | $(, $pba1:ident: $ba1:tt)* ; // BA1 pins 109 | $addressPins:ident 110 | [ $($pa:ident: $a:ident),* ] // Address pins 111 | ]),+) => { 112 | $( 113 | #[rustfmt::skip] 114 | /// 32-bit SDRAM 115 | impl 121 | PinsSdram<$pins, $addressPins> 122 | for (PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8, PA9, PA10, $($pa,)* 123 | PBA0, $($pba1,)* PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, 124 | PD8, PD9, PD10, PD11, PD12, PD13, PD14, PD15, PD16, PD17, 125 | PD18, PD19, PD20, PD21, PD22, PD23, PD24, PD25, PD26, PD27, 126 | PD28, PD29, PD30, PD31, PNBL0, PNBL1, PNBL2, PNBL3, PSDCKEn, 127 | PSDCLK, PSDNCAS, PSDNEn, PSDNRAS, PSDNWE) 128 | where PA0: A0, PA1: A1, PA2: A2, PA3: A3, PA4: A4, PA5: A5, PA6: A6, 129 | PA7: A7, PA8: A8, PA9: A9, PA10: A10, $($pa:$a,)* 130 | PBA0: BA0, $($pba1:$ba1,)* 131 | PD0: D0, PD1: D1, PD2: D2, PD3: D3, PD4: D4, PD5: D5, PD6: D6, 132 | PD7: D7, PD8: D8, PD9: D9, PD10: D10, PD11: D11, PD12: D12, 133 | PD13: D13, PD14: D14, PD15: D15, PD16: D16, PD17: D17, 134 | PD18: D18, PD19: D19, PD20: D20, PD21: D21, PD22: D22, 135 | PD23: D23, PD24: D24, PD25: D25, PD26: D26, PD27: D27, 136 | PD28: D28, PD29: D29, PD30: D30, PD31: D31, 137 | PNBL0: NBL0, PNBL1: NBL1, PNBL2: NBL2, PNBL3: NBL3, 138 | PSDCKEn: $ckeN, PSDCLK: SDCLK, 139 | PSDNCAS: SDNCAS, PSDNEn: $neN, PSDNRAS: SDNRAS, PSDNWE: SDNWE { 140 | 141 | const NUMBER_INTERNAL_BANKS: u8 = $nInternalB; 142 | } 143 | )+ 144 | } 145 | } 146 | 147 | #[cfg(feature = "sdram")] 148 | impl_16bit_sdram! { 149 | // 16-bit SDRAM with 11 address lines, BA0 only 150 | SdramBank1: [SDCKE0, SDNE0, 2; AddressPins11 []], 151 | SdramBank2: [SDCKE1, SDNE1, 2; AddressPins11 []], 152 | // 16-bit SDRAM with 11 address lines, BA0 and BA1 153 | SdramBank1: [SDCKE0, SDNE0, 4, PBA1: BA1; AddressPins11 []], 154 | SdramBank2: [SDCKE1, SDNE1, 4, PBA1: BA1; AddressPins11 []], 155 | // 16-bit SDRAM with 12 address lines, BA0 only 156 | SdramBank1: [SDCKE0, SDNE0, 2; AddressPins12 [PA11: A11]], 157 | SdramBank2: [SDCKE1, SDNE1, 2; AddressPins12 [PA11: A11]], 158 | // 16-bit SDRAM with 12 address lines, BA0 and BA1 159 | SdramBank1: [SDCKE0, SDNE0, 4, PBA1: BA1; AddressPins12 [PA11: A11]], 160 | SdramBank2: [SDCKE1, SDNE1, 4, PBA1: BA1; AddressPins12 [PA11: A11]], 161 | // 16-bit SDRAM with 13 address lines, BA0 only 162 | SdramBank1: [SDCKE0, SDNE0, 2; AddressPins13 [PA11: A11, PA12: A12]], 163 | SdramBank2: [SDCKE1, SDNE1, 2; AddressPins13 [PA11: A11, PA12: A12]], 164 | // 16-bit SDRAM with 13 address lines, BA0 and BA1 165 | SdramBank1: [SDCKE0, SDNE0, 4, PBA1: BA1; AddressPins13 [PA11: A11, PA12: A12]], 166 | SdramBank2: [SDCKE1, SDNE1, 4, PBA1: BA1; AddressPins13 [PA11: A11, PA12: A12]] 167 | } 168 | 169 | #[cfg(feature = "sdram")] 170 | impl_32bit_sdram! { 171 | // 32-bit SDRAM with 11 address lines, BA0 only 172 | SdramBank1: [SDCKE0, SDNE0, 2; AddressPins11 []], 173 | SdramBank2: [SDCKE1, SDNE1, 2; AddressPins11 []], 174 | // 32-bit SDRAM with 11 address lines, BA0 and BA1 175 | SdramBank1: [SDCKE0, SDNE0, 4, PBA1: BA1; AddressPins11 []], 176 | SdramBank2: [SDCKE1, SDNE1, 4, PBA1: BA1; AddressPins11 []], 177 | // 32-bit SDRAM with 12 address lines, BA0 only 178 | SdramBank1: [SDCKE0, SDNE0, 2; AddressPins12 [PA11: A11]], 179 | SdramBank2: [SDCKE1, SDNE1, 2; AddressPins12 [PA11: A11]], 180 | // 32-bit SDRAM with 12 address lines, BA0 and BA1 181 | SdramBank1: [SDCKE0, SDNE0, 4, PBA1: BA1; AddressPins12 [PA11: A11]], 182 | SdramBank2: [SDCKE1, SDNE1, 4, PBA1: BA1; AddressPins12 [PA11: A11]], 183 | // 32-bit SDRAM with 13 address lines, BA0 only 184 | SdramBank1: [SDCKE0, SDNE0, 2; AddressPins13 [PA11: A11, PA12: A12]], 185 | SdramBank2: [SDCKE1, SDNE1, 2; AddressPins13 [PA11: A11, PA12: A12]], 186 | // 32-bit SDRAM with 13 address lines, BA0 and BA1 187 | SdramBank1: [SDCKE0, SDNE0, 4, PBA1: BA1; AddressPins13 [PA11: A11, PA12: A12]], 188 | SdramBank2: [SDCKE1, SDNE1, 4, PBA1: BA1; AddressPins13 [PA11: A11, PA12: A12]] 189 | } 190 | 191 | // ---- NAND ---- 192 | 193 | #[cfg(feature = "nand")] 194 | use crate::nand::PinsNand; 195 | 196 | #[cfg(feature = "nand")] 197 | #[rustfmt::skip] 198 | /// 8-bit NAND 199 | impl 200 | PinsNand 201 | for (ALE, CLE, PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PNCE, PNOE, PNWE, PNWAIT) 202 | where ALE: A17, CLE: A16, 203 | PD0: D0, PD1: D1, PD2: D2, PD3: D3, PD4: D4, PD5: D5, PD6: D6, PD7: D7, 204 | PNCE: NCE, PNOE: NOE, PNWE: NWE, PNWAIT: NWAIT { 205 | const N_DATA: usize = 8; 206 | } 207 | 208 | /// Marks a type as an A0 pin 209 | pub trait A0 {} 210 | /// Marks a type as an A1 pin 211 | pub trait A1 {} 212 | /// Marks a type as an A10 pin 213 | pub trait A10 {} 214 | /// Marks a type as an A11 pin 215 | pub trait A11 {} 216 | /// Marks a type as an A12 pin 217 | pub trait A12 {} 218 | /// Marks a type as an A13 pin 219 | pub trait A13 {} 220 | /// Marks a type as an A14 pin 221 | pub trait A14 {} 222 | /// Marks a type as an A15 pin 223 | pub trait A15 {} 224 | /// Marks a type as an A16 pin 225 | pub trait A16 {} 226 | /// Marks a type as an A17 pin 227 | pub trait A17 {} 228 | /// Marks a type as an A18 pin 229 | pub trait A18 {} 230 | /// Marks a type as an A19 pin 231 | pub trait A19 {} 232 | /// Marks a type as an A2 pin 233 | pub trait A2 {} 234 | /// Marks a type as an A20 pin 235 | pub trait A20 {} 236 | /// Marks a type as an A21 pin 237 | pub trait A21 {} 238 | /// Marks a type as an A22 pin 239 | pub trait A22 {} 240 | /// Marks a type as an A23 pin 241 | pub trait A23 {} 242 | /// Marks a type as an A24 pin 243 | pub trait A24 {} 244 | /// Marks a type as an A25 pin 245 | pub trait A25 {} 246 | /// Marks a type as an A3 pin 247 | pub trait A3 {} 248 | /// Marks a type as an A4 pin 249 | pub trait A4 {} 250 | /// Marks a type as an A5 pin 251 | pub trait A5 {} 252 | /// Marks a type as an A6 pin 253 | pub trait A6 {} 254 | /// Marks a type as an A7 pin 255 | pub trait A7 {} 256 | /// Marks a type as an A8 pin 257 | pub trait A8 {} 258 | /// Marks a type as an A9 pin 259 | pub trait A9 {} 260 | /// Marks a type as a BA0 pin 261 | pub trait BA0 {} 262 | /// Marks a type as a BA1 pin 263 | pub trait BA1 {} 264 | /// Marks a type as a CLK pin 265 | pub trait CLK {} 266 | /// Marks a type as a D0 pin 267 | pub trait D0 {} 268 | /// Marks a type as a D1 pin 269 | pub trait D1 {} 270 | /// Marks a type as a D10 pin 271 | pub trait D10 {} 272 | /// Marks a type as a D11 pin 273 | pub trait D11 {} 274 | /// Marks a type as a D12 pin 275 | pub trait D12 {} 276 | /// Marks a type as a D13 pin 277 | pub trait D13 {} 278 | /// Marks a type as a D14 pin 279 | pub trait D14 {} 280 | /// Marks a type as a D15 pin 281 | pub trait D15 {} 282 | /// Marks a type as a D16 pin 283 | pub trait D16 {} 284 | /// Marks a type as a D17 pin 285 | pub trait D17 {} 286 | /// Marks a type as a D18 pin 287 | pub trait D18 {} 288 | /// Marks a type as a D19 pin 289 | pub trait D19 {} 290 | /// Marks a type as a D2 pin 291 | pub trait D2 {} 292 | /// Marks a type as a D20 pin 293 | pub trait D20 {} 294 | /// Marks a type as a D21 pin 295 | pub trait D21 {} 296 | /// Marks a type as a D22 pin 297 | pub trait D22 {} 298 | /// Marks a type as a D23 pin 299 | pub trait D23 {} 300 | /// Marks a type as a D24 pin 301 | pub trait D24 {} 302 | /// Marks a type as a D25 pin 303 | pub trait D25 {} 304 | /// Marks a type as a D26 pin 305 | pub trait D26 {} 306 | /// Marks a type as a D27 pin 307 | pub trait D27 {} 308 | /// Marks a type as a D28 pin 309 | pub trait D28 {} 310 | /// Marks a type as a D29 pin 311 | pub trait D29 {} 312 | /// Marks a type as a D3 pin 313 | pub trait D3 {} 314 | /// Marks a type as a D30 pin 315 | pub trait D30 {} 316 | /// Marks a type as a D31 pin 317 | pub trait D31 {} 318 | /// Marks a type as a D4 pin 319 | pub trait D4 {} 320 | /// Marks a type as a D5 pin 321 | pub trait D5 {} 322 | /// Marks a type as a D6 pin 323 | pub trait D6 {} 324 | /// Marks a type as a D7 pin 325 | pub trait D7 {} 326 | /// Marks a type as a D8 pin 327 | pub trait D8 {} 328 | /// Marks a type as a D9 pin 329 | pub trait D9 {} 330 | /// Marks a type as a DA0 pin 331 | pub trait DA0 {} 332 | /// Marks a type as a DA1 pin 333 | pub trait DA1 {} 334 | /// Marks a type as a DA10 pin 335 | pub trait DA10 {} 336 | /// Marks a type as a DA11 pin 337 | pub trait DA11 {} 338 | /// Marks a type as a DA12 pin 339 | pub trait DA12 {} 340 | /// Marks a type as a DA13 pin 341 | pub trait DA13 {} 342 | /// Marks a type as a DA14 pin 343 | pub trait DA14 {} 344 | /// Marks a type as a DA15 pin 345 | pub trait DA15 {} 346 | /// Marks a type as a DA2 pin 347 | pub trait DA2 {} 348 | /// Marks a type as a DA3 pin 349 | pub trait DA3 {} 350 | /// Marks a type as a DA4 pin 351 | pub trait DA4 {} 352 | /// Marks a type as a DA5 pin 353 | pub trait DA5 {} 354 | /// Marks a type as a DA6 pin 355 | pub trait DA6 {} 356 | /// Marks a type as a DA7 pin 357 | pub trait DA7 {} 358 | /// Marks a type as a DA8 pin 359 | pub trait DA8 {} 360 | /// Marks a type as a DA9 pin 361 | pub trait DA9 {} 362 | /// Marks a type as an INT pin 363 | pub trait INT {} 364 | /// Marks a type as a NBL0 pin 365 | pub trait NBL0 {} 366 | /// Marks a type as a NBL1 pin 367 | pub trait NBL1 {} 368 | /// Marks a type as a NBL2 pin 369 | pub trait NBL2 {} 370 | /// Marks a type as a NBL3 pin 371 | pub trait NBL3 {} 372 | /// Marks a type as a NE1 pin 373 | pub trait NE1 {} 374 | /// Marks a type as a NE2 pin 375 | pub trait NE2 {} 376 | /// Marks a type as a NE3 pin 377 | pub trait NE3 {} 378 | /// Marks a type as a NE4 pin 379 | pub trait NE4 {} 380 | /// Marks a type as a NL pin 381 | pub trait NL {} 382 | /// Marks a type as a NCE pin 383 | pub trait NCE {} 384 | /// Marks a type as a NOE pin 385 | pub trait NOE {} 386 | /// Marks a type as a NWAIT pin 387 | pub trait NWAIT {} 388 | /// Marks a type as a NWE pin 389 | pub trait NWE {} 390 | /// Marks a type as a SDCKE0 pin 391 | pub trait SDCKE0 {} 392 | /// Marks a type as a SDCKE1 pin 393 | pub trait SDCKE1 {} 394 | /// Marks a type as a SDCLK pin 395 | pub trait SDCLK {} 396 | /// Marks a type as a SDNCAS pin 397 | pub trait SDNCAS {} 398 | /// Marks a type as a SDNE0 pin 399 | pub trait SDNE0 {} 400 | /// Marks a type as a SDNE1 pin 401 | pub trait SDNE1 {} 402 | /// Marks a type as a SDNRAS pin 403 | pub trait SDNRAS {} 404 | /// Marks a type as a SDNWE pin 405 | pub trait SDNWE {} 406 | 407 | use crate::ral::fmc; 408 | use crate::FmcPeripheral; 409 | 410 | #[derive(Copy, Clone)] 411 | pub(crate) struct FmcRegisters(usize); 412 | 413 | impl FmcRegisters { 414 | #[inline(always)] 415 | pub fn new() -> Self { 416 | Self(FMC::REGISTERS as usize) 417 | } 418 | 419 | #[inline(always)] 420 | pub fn global(&self) -> &'static fmc::RegisterBlock { 421 | unsafe { &*(self.0 as *const _) } 422 | } 423 | } 424 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Hardware Abstraction Layer for STM32 Memory Controllers (FMC/FSMC) 2 | //! 3 | //! 4 | //! # Implementation Guide 5 | //! 6 | //! You can use the functionality in this crate by implementing the 7 | //! [`FmcPeripheral`](FmcPeripheral) trait. You should implement this trait for a 8 | //! structure that: 9 | //! 10 | //! * Takes ownership of the `FMC`/`FSMC` peripheral 11 | //! * Takes ownership of any structures / ZSTs related to the power or clock for the `FMC`/`FSMC` peripheral 12 | //! * Contains the frequency of the `FMC`/`FSMC` source clock (usually HCLK) 13 | //! 14 | //! A basic structure: 15 | //! 16 | //! ``` 17 | //! pub struct FMC { 18 | //! source_clock: u32, 19 | //! // any other fields here... 20 | //! } 21 | //! ``` 22 | //! 23 | //! An implementation of [`FmcPeripheral`](FmcPeripheral): 24 | //! 25 | //! ```rust 26 | //! # mod stm32 { pub struct FMC {} impl FMC { pub const fn ptr() -> *const u32 { &0 } } } 27 | //! # struct FMC { source_clock: u32 } 28 | //! use stm32_fmc::FmcPeripheral; 29 | //! 30 | //! unsafe impl Sync for FMC {} 31 | //! unsafe impl FmcPeripheral for FMC { 32 | //! const REGISTERS: *const () = stm32::FMC::ptr() as *const (); 33 | //! 34 | //! fn enable(&mut self) { 35 | //! // Enable and reset the FMC/FSMC using the RCC registers 36 | //! // Typically RCC.AHBxEN and RCC.AHBxRST 37 | //! } 38 | //! 39 | //! fn memory_controller_enable(&mut self) { 40 | //! // Only required if your part has an `FMCEN` bit 41 | //! } 42 | //! 43 | //! fn source_clock_hz(&self) -> u32 { 44 | //! self.source_clock 45 | //! } 46 | //! } 47 | //! ``` 48 | //! 49 | //! In a HAL, you can allow users to construct your structure by implementing a 50 | //! `new` method, or by making the fields public. 51 | //! 52 | //! ## Wrap constructor methods 53 | //! 54 | //! Each memory controller type ([`Sdram`](Sdram), [`Nand`](Nand), ..) provides both 55 | //! `new` and `new_unchecked` methods. 56 | //! 57 | //! For the convenience of users, you may want to wrap these with your `new` method, 58 | //! so that each memory can be created from the peripheral in one step. 59 | //! 60 | //! ``` 61 | //! # mod stm32 { pub struct FMC {} } 62 | //! # type CoreClocks = u32; 63 | //! # struct FMC {} 64 | //! # impl FMC { pub fn new(_: stm32::FMC, _: &CoreClocks) -> Self { Self {} } } 65 | //! # unsafe impl stm32_fmc::FmcPeripheral for FMC { 66 | //! # const REGISTERS: *const () = &0 as *const _ as *const (); 67 | //! # fn enable(&mut self) { } 68 | //! # fn source_clock_hz(&self) -> u32 { 0 } 69 | //! # } 70 | //! use stm32_fmc::{ 71 | //! AddressPinSet, PinsSdram, Sdram, SdramChip, SdramPinSet, SdramTargetBank, 72 | //! }; 73 | //! 74 | //! impl FMC { 75 | //! /// A new SDRAM memory via the Flexible Memory Controller 76 | //! pub fn sdram< 77 | //! BANK: SdramPinSet, 78 | //! ADDR: AddressPinSet, 79 | //! PINS: PinsSdram, 80 | //! CHIP: SdramChip, 81 | //! >( 82 | //! fmc: stm32::FMC, 83 | //! pins: PINS, 84 | //! chip: CHIP, 85 | //! clocks: &CoreClocks, 86 | //! ) -> Sdram { 87 | //! let fmc = Self::new(fmc, clocks); 88 | //! Sdram::new(fmc, pins, chip) 89 | //! } 90 | //! 91 | //! /// A new SDRAM memory via the Flexible Memory Controller 92 | //! pub fn sdram_unchecked>( 93 | //! fmc: stm32::FMC, 94 | //! bank: BANK, 95 | //! chip: CHIP, 96 | //! clocks: &CoreClocks, 97 | //! ) -> Sdram { 98 | //! let fmc = Self::new(fmc, clocks); 99 | //! Sdram::new_unchecked(fmc, bank, chip) 100 | //! } 101 | //! } 102 | //! ``` 103 | //! 104 | //! # Pin implementations 105 | //! 106 | //! In contrast with the `new_unchecked` methods, the `new` methods require the user 107 | //! pass a tuple as the `pins` argument. In a HAL, you can mark which types are 108 | //! suitable as follows: 109 | //! 110 | //! ```rust 111 | //! # pub use core::marker::PhantomData; 112 | //! # struct AF12 {} 113 | //! # struct Alternate { _af: PhantomData } 114 | //! # mod gpiof { pub use core::marker::PhantomData; pub struct PF0 { _a: PhantomData } } 115 | //! impl stm32_fmc::A0 for gpiof::PF0> {} 116 | //! // ... 117 | //! ``` 118 | //! 119 | 120 | #![no_std] 121 | // rustc lints. 122 | #![warn( 123 | bare_trait_objects, 124 | missing_copy_implementations, 125 | missing_debug_implementations, 126 | missing_docs, 127 | trivial_casts, 128 | trivial_numeric_casts, 129 | unused_extern_crates, 130 | unused_qualifications, 131 | unused_results 132 | )] 133 | 134 | #[macro_use] 135 | mod macros; 136 | 137 | mod fmc; 138 | pub use fmc::*; 139 | 140 | #[cfg(feature = "sdram")] 141 | mod sdram; 142 | #[cfg(feature = "sdram")] 143 | pub use sdram::{ 144 | PinsSdram, Sdram, SdramChip, SdramConfiguration, SdramPinSet, 145 | SdramTargetBank, SdramTiming, 146 | }; 147 | 148 | #[cfg(feature = "nand")] 149 | mod nand; 150 | #[cfg(feature = "nand")] 151 | pub use nand::device as nand_device; 152 | #[cfg(feature = "nand")] 153 | pub use nand::{Nand, NandChip, NandConfiguration, NandTiming, PinsNand}; 154 | 155 | /// Memory device definitions 156 | pub mod devices; 157 | 158 | mod ral; 159 | 160 | /// A trait for device-specific FMC peripherals. Implement this to add support 161 | /// for a new hardware platform. Peripherals that have this trait must have the 162 | /// same register block as STM32 FMC peripherals. 163 | pub unsafe trait FmcPeripheral: Send { 164 | /// Pointer to the register block 165 | const REGISTERS: *const (); 166 | 167 | /// Enables the FMC on its peripheral bus 168 | fn enable(&mut self); 169 | 170 | /// Enables the FMC memory controller (not always required) 171 | fn memory_controller_enable(&mut self) {} 172 | 173 | /// The frequency of the clock used as a source for the fmc_clk. 174 | /// 175 | /// F4/F7/G4: hclk 176 | /// H7: fmc_ker_ck 177 | fn source_clock_hz(&self) -> u32; 178 | } 179 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | #[cfg(all(feature = "defmt", feature = "log"))] 2 | compile_error!("You may not enable both `defmt` and `log` features."); 3 | 4 | #[cfg(feature = "log")] 5 | #[macro_use] 6 | mod log { 7 | macro_rules! fmc_log { 8 | (trace, $($arg:expr),*) => { log::trace!($($arg),*); }; 9 | } 10 | } 11 | 12 | #[cfg(feature = "defmt")] 13 | #[macro_use] 14 | mod log { 15 | macro_rules! fmc_log { 16 | (trace, $($arg:expr),*) => { ::defmt::trace!($($arg),*); }; 17 | } 18 | } 19 | 20 | #[cfg(all(not(feature = "log"), not(feature = "defmt")))] 21 | #[macro_use] 22 | mod log { 23 | macro_rules! fmc_log { 24 | ($level:ident, $($arg:expr),*) => { $( let _ = $arg; )* } 25 | } 26 | } 27 | 28 | macro_rules! fmc_trace { 29 | ($($arg:expr),*) => (fmc_log!(trace, $($arg),*)); 30 | } 31 | -------------------------------------------------------------------------------- /src/nand.rs: -------------------------------------------------------------------------------- 1 | //! HAL for FMC peripheral used to access NAND Flash 2 | //! 3 | 4 | use core::cmp; 5 | use core::marker::PhantomData; 6 | 7 | use embedded_hal::delay::DelayNs; 8 | 9 | use crate::fmc::{FmcBank, FmcRegisters}; 10 | use crate::FmcPeripheral; 11 | 12 | use crate::ral::{fmc, modify_reg}; 13 | 14 | pub mod device; 15 | 16 | /// FMC NAND Physical Interface Configuration 17 | /// 18 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 19 | #[derive(Clone, Copy, Debug, PartialEq)] 20 | pub struct NandConfiguration { 21 | /// Data path width in bits 22 | pub data_width: u8, 23 | /// Number of address bits used for the column address 24 | pub column_bits: u8, 25 | } 26 | 27 | /// FMC NAND Timing parameters 28 | /// 29 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 30 | #[derive(Clone, Copy, Debug, PartialEq)] 31 | pub struct NandTiming { 32 | /// nCE setup time tCS 33 | pub nce_setup_time: i32, 34 | /// Data setup time tDS 35 | pub data_setup_time: i32, 36 | /// ALE hold time 37 | pub ale_hold_time: i32, 38 | /// CLE hold time 39 | pub cle_hold_time: i32, 40 | /// ALE to nRE delay 41 | pub ale_to_nre_delay: i32, 42 | /// CLE to nRE delay 43 | pub cle_to_nre_delay: i32, 44 | /// nRE pulse width tRP 45 | pub nre_pulse_width_ns: i32, 46 | /// nWE pulse width tWP 47 | pub nwe_pulse_width_ns: i32, 48 | /// Read cycle time tRC 49 | pub read_cycle_time_ns: i32, 50 | /// Write cycle time tWC 51 | pub write_cycle_time_ns: i32, 52 | /// nWE high to busy tWB 53 | pub nwe_high_to_busy_ns: i32, 54 | } 55 | 56 | /// Respresents a model of NAND chip 57 | pub trait NandChip { 58 | /// NAND controller configuration 59 | const CONFIG: NandConfiguration; 60 | /// Timing parameters 61 | const TIMING: NandTiming; 62 | } 63 | 64 | /// FMC Peripheral specialized as a NAND Controller. Not yet initialized. 65 | #[allow(missing_debug_implementations)] 66 | pub struct Nand { 67 | /// Parameters for the NAND IC 68 | _chip: PhantomData, 69 | /// FMC peripheral 70 | fmc: FMC, 71 | /// Register access 72 | regs: FmcRegisters, 73 | } 74 | 75 | /// Set of pins for a NAND 76 | pub trait PinsNand { 77 | /// Number of data bus pins 78 | const N_DATA: usize; 79 | } 80 | 81 | impl Nand { 82 | /// New NAND instance 83 | /// 84 | /// `_pins` must be a set of pins connecting to an NAND on the FMC 85 | /// controller 86 | /// 87 | /// # Panics 88 | /// 89 | /// * Panics if there is a mismatch between the data lines in `PINS` and the 90 | /// NAND device 91 | pub fn new(fmc: FMC, _pins: PINS, _chip: IC) -> Self 92 | where 93 | PINS: PinsNand, 94 | { 95 | assert!( 96 | PINS::N_DATA == IC::CONFIG.data_width as usize, 97 | "NAND Data Bus Width mismatch between IC and controller" 98 | ); 99 | 100 | Nand { 101 | _chip: PhantomData, 102 | fmc, 103 | regs: FmcRegisters::new::(), 104 | } 105 | } 106 | 107 | /// New NAND instance 108 | /// 109 | /// # Safety 110 | /// 111 | /// This method does not ensure that IO pins are configured 112 | /// correctly. Misconfiguration may result in a bus lockup or stall when 113 | /// attempting to initialise the NAND device. 114 | /// 115 | /// The pins are not checked against the requirements for the NAND 116 | /// chip. Using this method it is possible to initialise a NAND device 117 | /// without sufficient pins to access the whole memory 118 | /// 119 | pub unsafe fn new_unchecked(fmc: FMC, _chip: IC) -> Self { 120 | Nand { 121 | _chip: PhantomData, 122 | fmc, 123 | regs: FmcRegisters::new::(), 124 | } 125 | } 126 | 127 | /// Initialise NAND instance. `delay` is used to wait 1µs after enabling the 128 | /// memory controller. 129 | /// 130 | /// Returns a [`NandDevice`](device::NandDevice) instance. 131 | /// 132 | /// # Panics 133 | /// 134 | /// * Panics if any setting in `IC::CONFIG` cannot be achieved 135 | /// * Panics if the FMC Kernel Clock is too fast to achieve the timing 136 | /// required by the NAND device 137 | pub fn init(&mut self, delay: &mut D) -> device::NandDevice 138 | where 139 | D: DelayNs, 140 | { 141 | // calculate clock period, round down 142 | let fmc_source_ck_hz = self.fmc.source_clock_hz(); 143 | let ker_clk_period_ns = 1_000_000_000u32 / fmc_source_ck_hz; 144 | 145 | // enable memory controller AHB register access 146 | self.fmc.enable(); 147 | 148 | // device features and timing 149 | self.set_features_timings(IC::CONFIG, IC::TIMING, ker_clk_period_ns); 150 | 151 | // enable memory controller 152 | self.fmc.memory_controller_enable(); 153 | delay.delay_us(1); 154 | 155 | // NOTE(unsafe): FMC controller has been initialized and enabled for 156 | // this bank 157 | unsafe { 158 | // Create device. NAND Flash is always on Bank 3 159 | let ptr = FmcBank::Bank3.ptr() as *mut u8; 160 | device::NandDevice::init(ptr, IC::CONFIG.column_bits as usize) 161 | } 162 | } 163 | 164 | /// Program memory device features and timings 165 | /// 166 | /// Timing calculations from AN4761 Section 4.2 167 | #[allow(non_snake_case)] 168 | fn set_features_timings( 169 | &mut self, 170 | config: NandConfiguration, 171 | timing: NandTiming, 172 | period_ns: u32, 173 | ) { 174 | let period_ns = period_ns as i32; 175 | let n_clock_periods = |time_ns: i32| { 176 | (time_ns + period_ns - 1) / period_ns // round up 177 | }; 178 | let t_CS = timing.nce_setup_time; 179 | let t_DS = timing.data_setup_time; 180 | let t_ALH = timing.ale_hold_time; 181 | let t_CLH = timing.cle_hold_time; 182 | let t_AR = timing.ale_to_nre_delay; 183 | let t_CLR = timing.cle_to_nre_delay; 184 | let t_RP = timing.nre_pulse_width_ns; 185 | let t_WP = timing.nwe_pulse_width_ns; 186 | let t_RC = timing.read_cycle_time_ns; 187 | let t_WC = timing.write_cycle_time_ns; 188 | let t_WB = timing.nwe_high_to_busy_ns; 189 | 190 | // setup time before RE/WE assertion 191 | let setup_time = cmp::max(t_CS, cmp::max(t_AR, t_CLR)); 192 | let set = cmp::max(n_clock_periods(setup_time - t_WP), 1) - 1; 193 | assert!(set < 255, "FMC ker clock too fast"); // 255 = reserved 194 | 195 | // RE/WE assertion time (minimum = 1) 196 | let wait = cmp::max(n_clock_periods(cmp::max(t_RP, t_WP)), 2) - 1; 197 | assert!(wait < 255, "FMC ker clock too fast"); // 255 = reserved 198 | 199 | // hold time after RE/WE deassertion (minimum = 1) 200 | let mut hold = cmp::max(n_clock_periods(cmp::max(t_ALH, t_CLH)), 1); 201 | // satisfy total cycle time 202 | let cycle_time = n_clock_periods(cmp::max(t_RC, t_WC)); 203 | while wait + 1 + hold + set + 1 < cycle_time { 204 | hold += 1; 205 | } 206 | assert!(hold < 255, "FMC ker clock too fast"); // 255 = reserved 207 | 208 | // hold time to meet t_WB timing 209 | let atthold = cmp::max(n_clock_periods(t_WB), 2) - 1; 210 | let atthold = cmp::max(atthold, hold); 211 | assert!(atthold < 255, "FMC ker clock too fast"); // 255 = reserved 212 | 213 | // CS assertion to data setup 214 | let hiz = cmp::max(n_clock_periods(t_CS + t_WP - t_DS), 0); 215 | assert!(hiz < 255, "FMC ker clock too fast"); // 255 = reserved 216 | 217 | // ALE low to RE assert 218 | let ale_to_nre = n_clock_periods(t_AR); 219 | let tar = cmp::max(ale_to_nre - set - 2, 0); 220 | assert!(tar < 16, "FMC ker clock too fast"); 221 | 222 | // CLE low to RE assert 223 | let clr_to_nre = n_clock_periods(t_CLR); 224 | let tclr = cmp::max(clr_to_nre - set - 2, 0); 225 | assert!(tclr < 16, "FMC ker clock too fast"); 226 | 227 | let data_width = match config.data_width { 228 | 8 => 0, 229 | 16 => 1, 230 | _ => panic!("not possible"), 231 | }; 232 | 233 | // PCR 234 | #[rustfmt::skip] 235 | modify_reg!(fmc, self.regs.global(), PCR, 236 | TAR: tar as u32, 237 | TCLR: tclr as u32, 238 | ECCPS: 1, // 0b1: 512 bytes 239 | ECCEN: 0, // 0b0: ECC computation disabled 240 | PWID: data_width, 241 | PTYP: 1, // 0b1: NAND Flash 242 | PWAITEN: 1 // 0b1: Wait feature enabled 243 | ); 244 | 245 | // PMEM: Common memory space timing register 246 | #[rustfmt::skip] 247 | modify_reg!(fmc, self.regs.global(), PMEM, 248 | MEMHIZ: hiz as u32, 249 | MEMHOLD: hold as u32, 250 | MEMWAIT: wait as u32, 251 | MEMSET: set as u32); 252 | 253 | // PATT: Attribute memory space timing register 254 | #[rustfmt::skip] 255 | modify_reg!(fmc, self.regs.global(), PATT, 256 | ATTHIZ: hiz as u32, 257 | ATTHOLD: atthold as u32, 258 | ATTWAIT: wait as u32, 259 | ATTSET: set as u32); 260 | 261 | // Enable 262 | #[rustfmt::skip] 263 | modify_reg!(fmc, self.regs.global(), PCR, 264 | PBKEN: 1); 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /src/nand/device.rs: -------------------------------------------------------------------------------- 1 | //! Management of external NAND Flash through the STM32 FMC peripheral 2 | //! 3 | //! Commands and parameters are referenced to the Open NAND Flash Interface 4 | //! (ONFI) Specification Revision 5.1 3 May 2022 5 | //! 6 | //! Addressing supports up to 64Gb / 4GByte (8-bit data) or 128Gb / 8Gbyte (16-bit data). 7 | 8 | use core::convert::TryInto; 9 | use core::sync::atomic::{fence, Ordering}; 10 | use core::{fmt, ptr, str}; 11 | 12 | /// NAND Commands defined in ONFI Specification 5.1 13 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 14 | #[derive(Clone, Copy, Debug, PartialEq)] 15 | #[allow(unused)] 16 | enum Command { 17 | /// 0xFF Reset: ONFI Section 5.3 18 | Reset = 0xFF, 19 | /// 0x90 Read ID: ONFI Section 5.6 20 | ReadID = 0x90, 21 | /// 0xEC Read Parameter Page: ONFI Section 5.7 22 | ReadParameterPage = 0xEC, 23 | /// 0xED Read Unique ID: ONFI Section 5.8 24 | ReadUniqueID = 0xED, 25 | /// Block Erase: ONFI Section 5.9 26 | BlockErase = 0x60, 27 | /// 0x70 Read Status: ONFI Section 5.10 28 | ReadStatus = 0x70, 29 | } 30 | 31 | /// Status returned from 0x70 Read Status: ONFI Section 5.10 32 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 33 | #[derive(Clone, Copy, Debug, PartialEq)] 34 | pub enum Status { 35 | /// Status Register indicated Pass 36 | Success(u8), 37 | /// Status Register indicates Fail 38 | Fail(u8), 39 | } 40 | impl Status { 41 | fn from_register(reg: u8) -> Self { 42 | match reg & 1 { 43 | 1 => Self::Fail(reg), 44 | _ => Self::Success(reg), 45 | } 46 | } 47 | } 48 | 49 | /// Identifier returned from 0x90 Read ID: ONFI Section 5.6 50 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 51 | #[derive(Clone, Copy, Debug, PartialEq)] 52 | pub struct ID { 53 | manufacturer_jedec: u8, 54 | device_jedec: u8, 55 | internal_chip_count: usize, 56 | page_size: usize, 57 | } 58 | 59 | /// Parameter Page returned from 0xEC Read Parameter Page: ONFI Section 5.7 60 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 61 | #[derive(Clone, Copy, PartialEq)] 62 | pub struct ParameterPage { 63 | signature: [u8; 4], 64 | onfi_revision: u16, 65 | manufacturer: [u8; 12], 66 | model: [u8; 20], 67 | date_code: u16, 68 | data_bytes_per_page: u32, 69 | spare_bytes_per_page: u16, 70 | pages_per_block: u32, 71 | blocks_per_lun: u32, 72 | lun_count: u8, 73 | ecc_bits: u8, 74 | } 75 | impl ParameterPage { 76 | /// Manufacturer of the device 77 | pub fn manufacturer(&self) -> &str { 78 | str::from_utf8(&self.manufacturer).unwrap_or("") 79 | } 80 | /// Model number of the deviceo 81 | pub fn model(&self) -> &str { 82 | str::from_utf8(&self.model).unwrap_or("") 83 | } 84 | } 85 | impl fmt::Debug for ParameterPage { 86 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 87 | f.debug_struct("ONFI Parameter Page") 88 | .field("ONFI Revision", &self.onfi_revision) 89 | .field("Manufacturer", &self.manufacturer()) 90 | .field("Model", &self.model()) 91 | .field("Date Code", &self.date_code) 92 | .field("Data bytes per Page", &self.data_bytes_per_page) 93 | .field("Spare bytes per Page", &self.spare_bytes_per_page) 94 | .field("Pages per Block", &self.pages_per_block) 95 | .field("Blocks per LUN", &self.blocks_per_lun) 96 | .field("LUN Count", &self.lun_count) 97 | .field("ECC Bits Correctability", &self.ecc_bits) 98 | .finish() 99 | } 100 | } 101 | 102 | /// NAND Device 103 | #[derive(Clone, Debug, PartialEq)] 104 | #[allow(missing_copy_implementations)] 105 | pub struct NandDevice { 106 | common_command: *mut u8, 107 | common_address: *mut u8, 108 | attribute_command: *mut u8, 109 | common_data: *mut u8, 110 | 111 | /// Number of address bits C that are used for the column address. The 112 | /// number of data bytes per page is typically 2^C 113 | column_bits: Option, 114 | } 115 | 116 | unsafe fn write_volatile_sync(dest: *mut T, src: T) { 117 | ptr::write_volatile(dest, src); 118 | 119 | // Ensure that the write is committed before continuing. In the default 120 | // ARMv7-M address map the space 0x8000_0000-0x9FFF_FFFF is Normal Memory 121 | // with write-though cache attribute. 122 | fence(Ordering::SeqCst); 123 | } 124 | 125 | impl NandDevice { 126 | /// Create a `NandDevice` from a bank pointer 127 | /// 128 | /// # Safety 129 | /// 130 | /// The FMC controller must have been initialized as NAND controller and 131 | /// enabled for this bank, with the correct pin settings. The bank pointer 132 | /// must be a singleton. 133 | pub(crate) unsafe fn init(ptr: *mut u8, column_bits: usize) -> NandDevice { 134 | let mut nand = NandDevice { 135 | common_command: ptr.add(0x1_0000), 136 | common_address: ptr.add(0x2_0000), 137 | attribute_command: ptr.add(0x801_0000), 138 | common_data: ptr, 139 | column_bits: Some(column_bits), 140 | }; 141 | 142 | // Reset Command. May be specifically required by some devices and there 143 | // seems to be no disadvantage of sending it always 144 | nand.reset(); 145 | 146 | nand 147 | } 148 | /// 0xFF Reset: ONFI Section 5.3 149 | pub fn reset(&mut self) { 150 | unsafe { 151 | write_volatile_sync(self.common_command, 0xFF); 152 | } 153 | } 154 | /// Generic Command 155 | fn command(&mut self, cmd: Command, address: u8, buffer: &mut [u8]) { 156 | unsafe { 157 | write_volatile_sync(self.common_command, cmd as u8); 158 | write_volatile_sync(self.common_address, address); 159 | for x in buffer { 160 | *x = ptr::read_volatile(self.common_data); 161 | } 162 | } 163 | } 164 | /// Generic Address 165 | /// 166 | /// column_bits must be set first! 167 | fn address(&mut self, address: usize, spare: bool) { 168 | let column_bits = self 169 | .column_bits 170 | .expect("Number of column bits must be configured first"); 171 | let column = (address & ((1 << column_bits) - 1)) 172 | + if spare { 1 << column_bits } else { 0 }; 173 | let row = address >> column_bits; 174 | 175 | let mut addr_cycles = [0u8; 5]; 176 | 177 | // Assuming 5-cycle address 178 | addr_cycles[0] = (column & 0xFF) as u8; 179 | addr_cycles[1] = ((column >> 8) & 0xFF) as u8; 180 | addr_cycles[2] = (row & 0xFF) as u8; 181 | addr_cycles[3] = ((row >> 8) & 0xFF) as u8; 182 | addr_cycles[4] = ((row >> 16) & 0xFF) as u8; 183 | 184 | for a in addr_cycles { 185 | unsafe { 186 | write_volatile_sync(self.common_address, a); 187 | } 188 | } 189 | } 190 | 191 | /// 0x90 Read ID: ONFI Section 5.6 192 | pub fn read_id(&mut self) -> ID { 193 | let mut id = [0u8; 5]; 194 | self.command(Command::ReadID, 0, &mut id); 195 | 196 | let internal_chip_count = match id[2] & 3 { 197 | 1 => 2, 198 | 2 => 4, 199 | 3 => 8, 200 | _ => 1, 201 | }; 202 | let page_size = match id[3] & 3 { 203 | 1 => 2048, 204 | 2 => 4096, 205 | _ => 0, 206 | }; 207 | ID { 208 | manufacturer_jedec: id[0], 209 | device_jedec: id[1], 210 | internal_chip_count, 211 | page_size, 212 | } 213 | } 214 | /// 0xEC Read Parameter Page: ONFI Section 5.7 215 | pub fn read_parameter_page(&mut self) -> ParameterPage { 216 | let mut page = [0u8; 115]; 217 | self.command(Command::ReadParameterPage, 0, &mut page); 218 | 219 | ParameterPage { 220 | signature: page[0..4].try_into().unwrap(), 221 | onfi_revision: u16::from_le_bytes(page[4..6].try_into().unwrap()), 222 | manufacturer: page[32..44].try_into().unwrap(), 223 | model: page[44..64].try_into().unwrap(), 224 | date_code: u16::from_le_bytes(page[65..67].try_into().unwrap()), 225 | data_bytes_per_page: u32::from_le_bytes( 226 | page[80..84].try_into().unwrap(), 227 | ), 228 | spare_bytes_per_page: u16::from_le_bytes( 229 | page[84..86].try_into().unwrap(), 230 | ), 231 | pages_per_block: u32::from_le_bytes( 232 | page[92..96].try_into().unwrap(), 233 | ), 234 | blocks_per_lun: u32::from_le_bytes( 235 | page[96..100].try_into().unwrap(), 236 | ), 237 | lun_count: page[100], 238 | ecc_bits: page[112], 239 | } 240 | } 241 | /// 0xED Read Unique ID: ONFI Section 5.8 242 | pub fn read_unique_id(&mut self) -> u128 { 243 | let mut unique = [0u8; 16]; 244 | self.command(Command::ReadUniqueID, 0, &mut unique); 245 | u128::from_le_bytes(unique) 246 | } 247 | /// 0x60 Block Erase: ONFI Section 5.9 248 | pub fn block_erase(&mut self, address: usize) -> Status { 249 | unsafe { 250 | write_volatile_sync(self.common_command, 0x60); // auto block erase setup 251 | } 252 | 253 | let column_bits = self 254 | .column_bits 255 | .expect("Number of column bits must be configured first!"); 256 | let row = address >> column_bits; 257 | unsafe { 258 | // write block address 259 | write_volatile_sync(self.common_address, (row & 0xFF) as u8); 260 | write_volatile_sync(self.common_address, ((row >> 8) & 0xFF) as u8); 261 | write_volatile_sync( 262 | self.common_address, 263 | ((row >> 16) & 0xFF) as u8, 264 | ); 265 | 266 | // erase command 267 | write_volatile_sync(self.attribute_command, 0xD0); // t_WB 268 | write_volatile_sync(self.common_command, Command::ReadStatus as u8); 269 | let status_register = ptr::read_volatile(self.common_data); 270 | Status::from_register(status_register) 271 | } 272 | } 273 | 274 | /// Page Read: ONFI Section 5.14 275 | /// 276 | /// This method starts a Page Read operation but does not include the data 277 | /// phase. This method is useful when DMA is used for the data phase. 278 | /// 279 | /// For a method that completes the entire transaction see 280 | /// [`page_read`](Self::page_read). 281 | pub fn start_page_read(&mut self, address: usize, spare: bool) { 282 | unsafe { 283 | write_volatile_sync(self.common_command, 0x00); 284 | self.address(address, spare); 285 | write_volatile_sync(self.attribute_command, 0x30); // t_WB 286 | } 287 | } 288 | /// Page Read: ONFI Section 5.14 289 | /// 290 | /// Executes a Page Read operation from the specified address. Data is 291 | /// copied to the slice `page`. The length of `page` determines the read 292 | /// length. The read length should not exceed the number of bytes between 293 | /// the specified address and the end of the page. Reading beyond the end of 294 | /// the page results in indeterminate values being returned. 295 | /// 296 | /// If `spare` is true, then the read occours from the spare area. The 297 | /// address offset from the start of the page plus the slice length should 298 | /// not exceed the spare area size. 299 | pub fn page_read(&mut self, address: usize, spare: bool, page: &mut [u8]) { 300 | self.start_page_read(address, spare); 301 | for x in page { 302 | unsafe { 303 | *x = ptr::read_volatile(self.common_data); 304 | } 305 | } 306 | } 307 | 308 | /// Page Program: ONFI Section 5.16 309 | /// 310 | /// Executes a page program to the specified address and waits for it to 311 | /// complete. The length of `page` determines the write length. The write 312 | /// length should not exceed the number of bytes between the specified 313 | /// address and the end of the page. Writing beyond this length is 314 | /// undefined. 315 | pub fn page_program( 316 | &mut self, 317 | address: usize, 318 | spare: bool, 319 | page: &[u8], 320 | ) -> Status { 321 | unsafe { 322 | write_volatile_sync(self.common_command, 0x80); // data input 323 | self.address(address, spare); 324 | for x in page { 325 | write_volatile_sync(self.common_data, *x); // write page 326 | } 327 | write_volatile_sync(self.attribute_command, 0x10); // program command, t_WB 328 | let mut status_register; 329 | while { 330 | write_volatile_sync( 331 | self.common_command, 332 | Command::ReadStatus as u8, 333 | ); 334 | status_register = ptr::read_volatile(self.common_data); 335 | 336 | status_register & 0x20 == 0 // program in progress 337 | } {} 338 | 339 | Status::from_register(status_register) 340 | } 341 | } 342 | } 343 | 344 | /// Methods to allow users to implement their own commands using `unsafe`. 345 | /// 346 | impl NandDevice { 347 | /// Return a Raw Pointer to the common command space. This memory-mapped 348 | /// address is used to write command phase of NAND device transactions. 349 | /// 350 | /// It is recommended to use 351 | /// [`ptr::write_volatile`](https://doc.rust-lang.org/std/ptr/fn.write_volatile.html) 352 | /// to write to this pointer. Depending on the memory map in use, you may 353 | /// need to ensure the write is committed by using 354 | /// [`core::atomic::sync::fence`](https://doc.rust-lang.org/core/sync/atomic/fn.fence.html). 355 | pub fn common_command(&mut self) -> *mut u8 { 356 | self.common_command 357 | } 358 | /// Return a Raw Pointer to the attribute command space. This memory-mapped 359 | /// address is used to write command phase of NAND device transactions. 360 | /// 361 | /// It is recommended to use 362 | /// [`ptr::write_volatile`](https://doc.rust-lang.org/std/ptr/fn.write_volatile.html) 363 | /// to write to this pointer. Depending on the memory map in use, you may 364 | /// need to ensure the write is committed by using 365 | /// [`core::atomic::sync::fence`](https://doc.rust-lang.org/core/sync/atomic/fn.fence.html). 366 | pub fn attribute_command(&mut self) -> *mut u8 { 367 | self.attribute_command 368 | } 369 | /// Return a Raw Pointer to the common address space. This memory-mapped 370 | /// address is used to write the address phase of NAND device transactions. 371 | /// 372 | /// It is recommended to use 373 | /// [`ptr::write_volatile`](https://doc.rust-lang.org/std/ptr/fn.write_volatile.html) 374 | /// to write to this pointer. Depending on the memory map in use, you may 375 | /// need to ensure the write is committed by using 376 | /// [`core::atomic::sync::fence`](https://doc.rust-lang.org/core/sync/atomic/fn.fence.html). 377 | pub fn common_address(&mut self) -> *mut u8 { 378 | self.common_address 379 | } 380 | /// Return a Raw Pointer to the common data space. This memory-mapped 381 | /// address is used to write or read the data phase of NAND device 382 | /// transactions. 383 | /// 384 | /// It is recommended to use 385 | /// [`ptr::write_volatile`](https://doc.rust-lang.org/std/ptr/fn.write_volatile.html) 386 | /// to write to this pointer. Depending on the memory map in use, you may 387 | /// need to ensure the write is committed by using 388 | /// [`core::atomic::sync::fence`](https://doc.rust-lang.org/core/sync/atomic/fn.fence.html). 389 | pub fn common_data(&mut self) -> *mut u8 { 390 | self.common_data 391 | } 392 | } 393 | -------------------------------------------------------------------------------- /src/ral/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | pub mod peripherals; 4 | pub mod register; 5 | 6 | pub use crate::{modify_reg, read_reg, write_reg}; 7 | 8 | pub mod fmc { 9 | pub use super::peripherals::fmc::*; 10 | } 11 | -------------------------------------------------------------------------------- /src/ral/peripherals/fmc.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case, non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | //! Flexible memory controller 4 | //! 5 | //! With the caveat that SDCMR:MRD is 13-bits wide on these parts: 6 | //! 7 | //! Used by: stm32f469, stm32f479 8 | //! Used by: stm32f745, stm32f765, stm32f7x6, stm32f7x7, stm32f7x9 9 | //! 10 | //! With the caveat that BCR1:{FMCEN,BMAP} are not included: 11 | //! 12 | //! Used by: stm32h743, stm32h743v, stm32h747cm4, stm32h747cm7, stm32h753, stm32h753v 13 | 14 | use super::super::register::{RORegister, RWRegister}; 15 | #[cfg(not(feature = "nosync"))] 16 | use core::marker::PhantomData; 17 | 18 | /// SRAM/NOR-Flash chip-select control register 1 19 | pub mod BCR1 { 20 | 21 | /// CCLKEN 22 | pub mod CCLKEN { 23 | /// Offset (20 bits) 24 | pub const offset: u32 = 20; 25 | /// Mask (1 bit: 1 << 20) 26 | pub const mask: u32 = 1 << offset; 27 | /// Read-only values (empty) 28 | pub mod R {} 29 | /// Write-only values (empty) 30 | pub mod W {} 31 | /// Read-write values 32 | pub mod RW { 33 | 34 | /// 0b1: The FMC_CLK is only generated during the synchronous memory access (read/write transaction) 35 | pub const Enabled: u32 = 0b1; 36 | 37 | /// 0b0: The FMC_CLK is generated continuously during asynchronous and synchronous access. The FMC_CLK clock is activated when the CCLKEN is set 38 | pub const Disabled: u32 = 0b0; 39 | } 40 | } 41 | 42 | /// CBURSTRW 43 | pub mod CBURSTRW { 44 | /// Offset (19 bits) 45 | pub const offset: u32 = 19; 46 | /// Mask (1 bit: 1 << 19) 47 | pub const mask: u32 = 1 << offset; 48 | /// Read-only values (empty) 49 | pub mod R {} 50 | /// Write-only values (empty) 51 | pub mod W {} 52 | /// Read-write values 53 | pub mod RW { 54 | 55 | /// 0b1: Write operations are performed in synchronous mode 56 | pub const Enabled: u32 = 0b1; 57 | 58 | /// 0b0: Write operations are always performed in asynchronous mode 59 | pub const Disabled: u32 = 0b0; 60 | } 61 | } 62 | 63 | /// ASYNCWAIT 64 | pub mod ASYNCWAIT { 65 | /// Offset (15 bits) 66 | pub const offset: u32 = 15; 67 | /// Mask (1 bit: 1 << 15) 68 | pub const mask: u32 = 1 << offset; 69 | /// Read-only values (empty) 70 | pub mod R {} 71 | /// Write-only values (empty) 72 | pub mod W {} 73 | /// Read-write values 74 | pub mod RW { 75 | 76 | /// 0b0: Wait signal not used in asynchronous mode 77 | pub const Disabled: u32 = 0b0; 78 | 79 | /// 0b1: Wait signal used even in asynchronous mode 80 | pub const Enabled: u32 = 0b1; 81 | } 82 | } 83 | 84 | /// EXTMOD 85 | pub mod EXTMOD { 86 | /// Offset (14 bits) 87 | pub const offset: u32 = 14; 88 | /// Mask (1 bit: 1 << 14) 89 | pub const mask: u32 = 1 << offset; 90 | /// Read-only values (empty) 91 | pub mod R {} 92 | /// Write-only values (empty) 93 | pub mod W {} 94 | /// Read-write values 95 | pub mod RW { 96 | 97 | /// 0b0: Values inside the FMC_BWTR are not taken into account 98 | pub const Disabled: u32 = 0b0; 99 | 100 | /// 0b1: Values inside the FMC_BWTR are taken into account 101 | pub const Enabled: u32 = 0b1; 102 | } 103 | } 104 | 105 | /// WAITEN 106 | pub mod WAITEN { 107 | /// Offset (13 bits) 108 | pub const offset: u32 = 13; 109 | /// Mask (1 bit: 1 << 13) 110 | pub const mask: u32 = 1 << offset; 111 | /// Read-only values (empty) 112 | pub mod R {} 113 | /// Write-only values (empty) 114 | pub mod W {} 115 | /// Read-write values 116 | pub mod RW { 117 | 118 | /// 0b0: Values inside the FMC_BWTR are taken into account 119 | pub const Disabled: u32 = 0b0; 120 | 121 | /// 0b1: NWAIT signal enabled 122 | pub const Enabled: u32 = 0b1; 123 | } 124 | } 125 | 126 | /// WREN 127 | pub mod WREN { 128 | /// Offset (12 bits) 129 | pub const offset: u32 = 12; 130 | /// Mask (1 bit: 1 << 12) 131 | pub const mask: u32 = 1 << offset; 132 | /// Read-only values (empty) 133 | pub mod R {} 134 | /// Write-only values (empty) 135 | pub mod W {} 136 | /// Read-write values 137 | pub mod RW { 138 | 139 | /// 0b0: Write operations disabled for the bank by the FMC 140 | pub const Disabled: u32 = 0b0; 141 | 142 | /// 0b1: Write operations enabled for the bank by the FMC 143 | pub const Enabled: u32 = 0b1; 144 | } 145 | } 146 | 147 | /// WAITCFG 148 | pub mod WAITCFG { 149 | /// Offset (11 bits) 150 | pub const offset: u32 = 11; 151 | /// Mask (1 bit: 1 << 11) 152 | pub const mask: u32 = 1 << offset; 153 | /// Read-only values (empty) 154 | pub mod R {} 155 | /// Write-only values (empty) 156 | pub mod W {} 157 | /// Read-write values 158 | pub mod RW { 159 | 160 | /// 0b0: NWAIT signal is active one data cycle before wait state 161 | pub const BeforeWaitState: u32 = 0b0; 162 | 163 | /// 0b1: NWAIT signal is active during wait state 164 | pub const DuringWaitState: u32 = 0b1; 165 | } 166 | } 167 | 168 | /// WAITPOL 169 | pub mod WAITPOL { 170 | /// Offset (9 bits) 171 | pub const offset: u32 = 9; 172 | /// Mask (1 bit: 1 << 9) 173 | pub const mask: u32 = 1 << offset; 174 | /// Read-only values (empty) 175 | pub mod R {} 176 | /// Write-only values (empty) 177 | pub mod W {} 178 | /// Read-write values 179 | pub mod RW { 180 | 181 | /// 0b0: NWAIT active low 182 | pub const ActiveLow: u32 = 0b0; 183 | 184 | /// 0b1: NWAIT active high 185 | pub const ActiveHigh: u32 = 0b1; 186 | } 187 | } 188 | 189 | /// BURSTEN 190 | pub mod BURSTEN { 191 | /// Offset (8 bits) 192 | pub const offset: u32 = 8; 193 | /// Mask (1 bit: 1 << 8) 194 | pub const mask: u32 = 1 << offset; 195 | /// Read-only values (empty) 196 | pub mod R {} 197 | /// Write-only values (empty) 198 | pub mod W {} 199 | /// Read-write values 200 | pub mod RW { 201 | 202 | /// 0b0: Burst mode disabled 203 | pub const Disabled: u32 = 0b0; 204 | 205 | /// 0b1: Burst mode enabled 206 | pub const Enabled: u32 = 0b1; 207 | } 208 | } 209 | 210 | /// FACCEN 211 | pub mod FACCEN { 212 | /// Offset (6 bits) 213 | pub const offset: u32 = 6; 214 | /// Mask (1 bit: 1 << 6) 215 | pub const mask: u32 = 1 << offset; 216 | /// Read-only values (empty) 217 | pub mod R {} 218 | /// Write-only values (empty) 219 | pub mod W {} 220 | /// Read-write values 221 | pub mod RW { 222 | 223 | /// 0b0: Corresponding NOR Flash memory access is disabled 224 | pub const Disabled: u32 = 0b0; 225 | 226 | /// 0b1: Corresponding NOR Flash memory access is enabled 227 | pub const Enabled: u32 = 0b1; 228 | } 229 | } 230 | 231 | /// MWID 232 | pub mod MWID { 233 | /// Offset (4 bits) 234 | pub const offset: u32 = 4; 235 | /// Mask (2 bits: 0b11 << 4) 236 | pub const mask: u32 = 0b11 << offset; 237 | /// Read-only values (empty) 238 | pub mod R {} 239 | /// Write-only values (empty) 240 | pub mod W {} 241 | /// Read-write values 242 | pub mod RW { 243 | 244 | /// 0b00: Memory data bus width 8 bits 245 | pub const Bits8: u32 = 0b00; 246 | 247 | /// 0b01: Memory data bus width 16 bits 248 | pub const Bits16: u32 = 0b01; 249 | 250 | /// 0b10: Memory data bus width 32 bits 251 | pub const Bits32: u32 = 0b10; 252 | } 253 | } 254 | 255 | /// MTYP 256 | pub mod MTYP { 257 | /// Offset (2 bits) 258 | pub const offset: u32 = 2; 259 | /// Mask (2 bits: 0b11 << 2) 260 | pub const mask: u32 = 0b11 << offset; 261 | /// Read-only values (empty) 262 | pub mod R {} 263 | /// Write-only values (empty) 264 | pub mod W {} 265 | /// Read-write values 266 | pub mod RW { 267 | 268 | /// 0b00: SRAM memory type 269 | pub const SRAM: u32 = 0b00; 270 | 271 | /// 0b01: PSRAM (CRAM) memory type 272 | pub const PSRAM: u32 = 0b01; 273 | 274 | /// 0b10: NOR Flash/OneNAND Flash 275 | pub const Flash: u32 = 0b10; 276 | } 277 | } 278 | 279 | /// MUXEN 280 | pub mod MUXEN { 281 | /// Offset (1 bits) 282 | pub const offset: u32 = 1; 283 | /// Mask (1 bit: 1 << 1) 284 | pub const mask: u32 = 1 << offset; 285 | /// Read-only values (empty) 286 | pub mod R {} 287 | /// Write-only values (empty) 288 | pub mod W {} 289 | /// Read-write values 290 | pub mod RW { 291 | 292 | /// 0b0: Address/Data non-multiplexed 293 | pub const Disabled: u32 = 0b0; 294 | 295 | /// 0b1: Address/Data multiplexed on databus 296 | pub const Enabled: u32 = 0b1; 297 | } 298 | } 299 | 300 | /// MBKEN 301 | pub mod MBKEN { 302 | /// Offset (0 bits) 303 | pub const offset: u32 = 0; 304 | /// Mask (1 bit: 1 << 0) 305 | pub const mask: u32 = 1 << offset; 306 | /// Read-only values (empty) 307 | pub mod R {} 308 | /// Write-only values (empty) 309 | pub mod W {} 310 | /// Read-write values 311 | pub mod RW { 312 | 313 | /// 0b0: Corresponding memory bank is disabled 314 | pub const Disabled: u32 = 0b0; 315 | 316 | /// 0b1: Corresponding memory bank is enabled 317 | pub const Enabled: u32 = 0b1; 318 | } 319 | } 320 | 321 | /// WRAPMOD 322 | pub mod WRAPMOD { 323 | /// Offset (10 bits) 324 | pub const offset: u32 = 10; 325 | /// Mask (1 bit: 1 << 10) 326 | pub const mask: u32 = 1 << offset; 327 | /// Read-only values (empty) 328 | pub mod R {} 329 | /// Write-only values (empty) 330 | pub mod W {} 331 | /// Read-write values (empty) 332 | pub mod RW {} 333 | } 334 | 335 | /// Write FIFO disable 336 | pub mod WFDIS { 337 | /// Offset (21 bits) 338 | pub const offset: u32 = 21; 339 | /// Mask (1 bit: 1 << 21) 340 | pub const mask: u32 = 1 << offset; 341 | /// Read-only values (empty) 342 | pub mod R {} 343 | /// Write-only values (empty) 344 | pub mod W {} 345 | /// Read-write values 346 | pub mod RW { 347 | 348 | /// 0b0: Write FIFO enabled 349 | pub const Enabled: u32 = 0b0; 350 | 351 | /// 0b1: Write FIFO disabled 352 | pub const Disabled: u32 = 0b1; 353 | } 354 | } 355 | 356 | /// CRAM page size 357 | pub mod CPSIZE { 358 | /// Offset (16 bits) 359 | pub const offset: u32 = 16; 360 | /// Mask (3 bits: 0b111 << 16) 361 | pub const mask: u32 = 0b111 << offset; 362 | /// Read-only values (empty) 363 | pub mod R {} 364 | /// Write-only values (empty) 365 | pub mod W {} 366 | /// Read-write values 367 | pub mod RW { 368 | 369 | /// 0b000: No burst split when crossing page boundary 370 | pub const NoBurstSplit: u32 = 0b000; 371 | 372 | /// 0b001: 128 bytes CRAM page size 373 | pub const Bytes128: u32 = 0b001; 374 | 375 | /// 0b010: 256 bytes CRAM page size 376 | pub const Bytes256: u32 = 0b010; 377 | 378 | /// 0b011: 512 bytes CRAM page size 379 | pub const Bytes512: u32 = 0b011; 380 | 381 | /// 0b100: 1024 bytes CRAM page size 382 | pub const Bytes1024: u32 = 0b100; 383 | } 384 | } 385 | } 386 | 387 | /// SRAM/NOR-Flash chip-select timing register 1 388 | pub mod BTR1 { 389 | 390 | /// ACCMOD 391 | pub mod ACCMOD { 392 | /// Offset (28 bits) 393 | pub const offset: u32 = 28; 394 | /// Mask (2 bits: 0b11 << 28) 395 | pub const mask: u32 = 0b11 << offset; 396 | /// Read-only values (empty) 397 | pub mod R {} 398 | /// Write-only values (empty) 399 | pub mod W {} 400 | /// Read-write values 401 | pub mod RW { 402 | 403 | /// 0b00: Access mode A 404 | pub const A: u32 = 0b00; 405 | 406 | /// 0b01: Access mode B 407 | pub const B: u32 = 0b01; 408 | 409 | /// 0b10: Access mode C 410 | pub const C: u32 = 0b10; 411 | 412 | /// 0b11: Access mode D 413 | pub const D: u32 = 0b11; 414 | } 415 | } 416 | 417 | /// DATLAT 418 | pub mod DATLAT { 419 | /// Offset (24 bits) 420 | pub const offset: u32 = 24; 421 | /// Mask (4 bits: 0b1111 << 24) 422 | pub const mask: u32 = 0b1111 << offset; 423 | /// Read-only values (empty) 424 | pub mod R {} 425 | /// Write-only values (empty) 426 | pub mod W {} 427 | /// Read-write values (empty) 428 | pub mod RW {} 429 | } 430 | 431 | /// CLKDIV 432 | pub mod CLKDIV { 433 | /// Offset (20 bits) 434 | pub const offset: u32 = 20; 435 | /// Mask (4 bits: 0b1111 << 20) 436 | pub const mask: u32 = 0b1111 << offset; 437 | /// Read-only values (empty) 438 | pub mod R {} 439 | /// Write-only values (empty) 440 | pub mod W {} 441 | /// Read-write values (empty) 442 | pub mod RW {} 443 | } 444 | 445 | /// BUSTURN 446 | pub mod BUSTURN { 447 | /// Offset (16 bits) 448 | pub const offset: u32 = 16; 449 | /// Mask (4 bits: 0b1111 << 16) 450 | pub const mask: u32 = 0b1111 << offset; 451 | /// Read-only values (empty) 452 | pub mod R {} 453 | /// Write-only values (empty) 454 | pub mod W {} 455 | /// Read-write values (empty) 456 | pub mod RW {} 457 | } 458 | 459 | /// DATAST 460 | pub mod DATAST { 461 | /// Offset (8 bits) 462 | pub const offset: u32 = 8; 463 | /// Mask (8 bits: 0xff << 8) 464 | pub const mask: u32 = 0xff << offset; 465 | /// Read-only values (empty) 466 | pub mod R {} 467 | /// Write-only values (empty) 468 | pub mod W {} 469 | /// Read-write values (empty) 470 | pub mod RW {} 471 | } 472 | 473 | /// ADDHLD 474 | pub mod ADDHLD { 475 | /// Offset (4 bits) 476 | pub const offset: u32 = 4; 477 | /// Mask (4 bits: 0b1111 << 4) 478 | pub const mask: u32 = 0b1111 << offset; 479 | /// Read-only values (empty) 480 | pub mod R {} 481 | /// Write-only values (empty) 482 | pub mod W {} 483 | /// Read-write values (empty) 484 | pub mod RW {} 485 | } 486 | 487 | /// ADDSET 488 | pub mod ADDSET { 489 | /// Offset (0 bits) 490 | pub const offset: u32 = 0; 491 | /// Mask (4 bits: 0b1111 << 0) 492 | pub const mask: u32 = 0b1111 << offset; 493 | /// Read-only values (empty) 494 | pub mod R {} 495 | /// Write-only values (empty) 496 | pub mod W {} 497 | /// Read-write values (empty) 498 | pub mod RW {} 499 | } 500 | } 501 | 502 | /// SRAM/NOR-Flash chip-select timing register 1 503 | pub mod BTR2 { 504 | pub use super::BTR1::ACCMOD; 505 | pub use super::BTR1::ADDHLD; 506 | pub use super::BTR1::ADDSET; 507 | pub use super::BTR1::BUSTURN; 508 | pub use super::BTR1::CLKDIV; 509 | pub use super::BTR1::DATAST; 510 | pub use super::BTR1::DATLAT; 511 | } 512 | 513 | /// SRAM/NOR-Flash chip-select timing register 1 514 | pub mod BTR3 { 515 | pub use super::BTR1::ACCMOD; 516 | pub use super::BTR1::ADDHLD; 517 | pub use super::BTR1::ADDSET; 518 | pub use super::BTR1::BUSTURN; 519 | pub use super::BTR1::CLKDIV; 520 | pub use super::BTR1::DATAST; 521 | pub use super::BTR1::DATLAT; 522 | } 523 | 524 | /// SRAM/NOR-Flash chip-select timing register 1 525 | pub mod BTR4 { 526 | pub use super::BTR1::ACCMOD; 527 | pub use super::BTR1::ADDHLD; 528 | pub use super::BTR1::ADDSET; 529 | pub use super::BTR1::BUSTURN; 530 | pub use super::BTR1::CLKDIV; 531 | pub use super::BTR1::DATAST; 532 | pub use super::BTR1::DATLAT; 533 | } 534 | 535 | /// SRAM/NOR-Flash chip-select control register 2 536 | pub mod BCR2 { 537 | 538 | /// CBURSTRW 539 | pub mod CBURSTRW { 540 | /// Offset (19 bits) 541 | pub const offset: u32 = 19; 542 | /// Mask (1 bit: 1 << 19) 543 | pub const mask: u32 = 1 << offset; 544 | /// Read-only values (empty) 545 | pub mod R {} 546 | /// Write-only values (empty) 547 | pub mod W {} 548 | /// Read-write values 549 | pub mod RW { 550 | 551 | /// 0b1: Write operations are performed in synchronous mode 552 | pub const Enabled: u32 = 0b1; 553 | 554 | /// 0b0: Write operations are always performed in asynchronous mode 555 | pub const Disabled: u32 = 0b0; 556 | } 557 | } 558 | 559 | /// ASYNCWAIT 560 | pub mod ASYNCWAIT { 561 | /// Offset (15 bits) 562 | pub const offset: u32 = 15; 563 | /// Mask (1 bit: 1 << 15) 564 | pub const mask: u32 = 1 << offset; 565 | /// Read-only values (empty) 566 | pub mod R {} 567 | /// Write-only values (empty) 568 | pub mod W {} 569 | /// Read-write values 570 | pub mod RW { 571 | 572 | /// 0b0: Wait signal not used in asynchronous mode 573 | pub const Disabled: u32 = 0b0; 574 | 575 | /// 0b1: Wait signal used even in asynchronous mode 576 | pub const Enabled: u32 = 0b1; 577 | } 578 | } 579 | 580 | /// EXTMOD 581 | pub mod EXTMOD { 582 | /// Offset (14 bits) 583 | pub const offset: u32 = 14; 584 | /// Mask (1 bit: 1 << 14) 585 | pub const mask: u32 = 1 << offset; 586 | /// Read-only values (empty) 587 | pub mod R {} 588 | /// Write-only values (empty) 589 | pub mod W {} 590 | /// Read-write values 591 | pub mod RW { 592 | 593 | /// 0b0: Values inside the FMC_BWTR are not taken into account 594 | pub const Disabled: u32 = 0b0; 595 | 596 | /// 0b1: Values inside the FMC_BWTR are taken into account 597 | pub const Enabled: u32 = 0b1; 598 | } 599 | } 600 | 601 | /// WAITEN 602 | pub mod WAITEN { 603 | /// Offset (13 bits) 604 | pub const offset: u32 = 13; 605 | /// Mask (1 bit: 1 << 13) 606 | pub const mask: u32 = 1 << offset; 607 | /// Read-only values (empty) 608 | pub mod R {} 609 | /// Write-only values (empty) 610 | pub mod W {} 611 | /// Read-write values 612 | pub mod RW { 613 | 614 | /// 0b0: Values inside the FMC_BWTR are taken into account 615 | pub const Disabled: u32 = 0b0; 616 | 617 | /// 0b1: NWAIT signal enabled 618 | pub const Enabled: u32 = 0b1; 619 | } 620 | } 621 | 622 | /// WREN 623 | pub mod WREN { 624 | /// Offset (12 bits) 625 | pub const offset: u32 = 12; 626 | /// Mask (1 bit: 1 << 12) 627 | pub const mask: u32 = 1 << offset; 628 | /// Read-only values (empty) 629 | pub mod R {} 630 | /// Write-only values (empty) 631 | pub mod W {} 632 | /// Read-write values 633 | pub mod RW { 634 | 635 | /// 0b0: Write operations disabled for the bank by the FMC 636 | pub const Disabled: u32 = 0b0; 637 | 638 | /// 0b1: Write operations enabled for the bank by the FMC 639 | pub const Enabled: u32 = 0b1; 640 | } 641 | } 642 | 643 | /// WAITCFG 644 | pub mod WAITCFG { 645 | /// Offset (11 bits) 646 | pub const offset: u32 = 11; 647 | /// Mask (1 bit: 1 << 11) 648 | pub const mask: u32 = 1 << offset; 649 | /// Read-only values (empty) 650 | pub mod R {} 651 | /// Write-only values (empty) 652 | pub mod W {} 653 | /// Read-write values 654 | pub mod RW { 655 | 656 | /// 0b0: NWAIT signal is active one data cycle before wait state 657 | pub const BeforeWaitState: u32 = 0b0; 658 | 659 | /// 0b1: NWAIT signal is active during wait state 660 | pub const DuringWaitState: u32 = 0b1; 661 | } 662 | } 663 | 664 | /// WRAPMOD 665 | pub mod WRAPMOD { 666 | /// Offset (10 bits) 667 | pub const offset: u32 = 10; 668 | /// Mask (1 bit: 1 << 10) 669 | pub const mask: u32 = 1 << offset; 670 | /// Read-only values (empty) 671 | pub mod R {} 672 | /// Write-only values (empty) 673 | pub mod W {} 674 | /// Read-write values (empty) 675 | pub mod RW {} 676 | } 677 | 678 | /// WAITPOL 679 | pub mod WAITPOL { 680 | /// Offset (9 bits) 681 | pub const offset: u32 = 9; 682 | /// Mask (1 bit: 1 << 9) 683 | pub const mask: u32 = 1 << offset; 684 | /// Read-only values (empty) 685 | pub mod R {} 686 | /// Write-only values (empty) 687 | pub mod W {} 688 | /// Read-write values 689 | pub mod RW { 690 | 691 | /// 0b0: NWAIT active low 692 | pub const ActiveLow: u32 = 0b0; 693 | 694 | /// 0b1: NWAIT active high 695 | pub const ActiveHigh: u32 = 0b1; 696 | } 697 | } 698 | 699 | /// BURSTEN 700 | pub mod BURSTEN { 701 | /// Offset (8 bits) 702 | pub const offset: u32 = 8; 703 | /// Mask (1 bit: 1 << 8) 704 | pub const mask: u32 = 1 << offset; 705 | /// Read-only values (empty) 706 | pub mod R {} 707 | /// Write-only values (empty) 708 | pub mod W {} 709 | /// Read-write values 710 | pub mod RW { 711 | 712 | /// 0b0: Burst mode disabled 713 | pub const Disabled: u32 = 0b0; 714 | 715 | /// 0b1: Burst mode enabled 716 | pub const Enabled: u32 = 0b1; 717 | } 718 | } 719 | 720 | /// FACCEN 721 | pub mod FACCEN { 722 | /// Offset (6 bits) 723 | pub const offset: u32 = 6; 724 | /// Mask (1 bit: 1 << 6) 725 | pub const mask: u32 = 1 << offset; 726 | /// Read-only values (empty) 727 | pub mod R {} 728 | /// Write-only values (empty) 729 | pub mod W {} 730 | /// Read-write values 731 | pub mod RW { 732 | 733 | /// 0b0: Corresponding NOR Flash memory access is disabled 734 | pub const Disabled: u32 = 0b0; 735 | 736 | /// 0b1: Corresponding NOR Flash memory access is enabled 737 | pub const Enabled: u32 = 0b1; 738 | } 739 | } 740 | 741 | /// MWID 742 | pub mod MWID { 743 | /// Offset (4 bits) 744 | pub const offset: u32 = 4; 745 | /// Mask (2 bits: 0b11 << 4) 746 | pub const mask: u32 = 0b11 << offset; 747 | /// Read-only values (empty) 748 | pub mod R {} 749 | /// Write-only values (empty) 750 | pub mod W {} 751 | /// Read-write values 752 | pub mod RW { 753 | 754 | /// 0b00: Memory data bus width 8 bits 755 | pub const Bits8: u32 = 0b00; 756 | 757 | /// 0b01: Memory data bus width 16 bits 758 | pub const Bits16: u32 = 0b01; 759 | 760 | /// 0b10: Memory data bus width 32 bits 761 | pub const Bits32: u32 = 0b10; 762 | } 763 | } 764 | 765 | /// MTYP 766 | pub mod MTYP { 767 | /// Offset (2 bits) 768 | pub const offset: u32 = 2; 769 | /// Mask (2 bits: 0b11 << 2) 770 | pub const mask: u32 = 0b11 << offset; 771 | /// Read-only values (empty) 772 | pub mod R {} 773 | /// Write-only values (empty) 774 | pub mod W {} 775 | /// Read-write values 776 | pub mod RW { 777 | 778 | /// 0b00: SRAM memory type 779 | pub const SRAM: u32 = 0b00; 780 | 781 | /// 0b01: PSRAM (CRAM) memory type 782 | pub const PSRAM: u32 = 0b01; 783 | 784 | /// 0b10: NOR Flash/OneNAND Flash 785 | pub const Flash: u32 = 0b10; 786 | } 787 | } 788 | 789 | /// MUXEN 790 | pub mod MUXEN { 791 | /// Offset (1 bits) 792 | pub const offset: u32 = 1; 793 | /// Mask (1 bit: 1 << 1) 794 | pub const mask: u32 = 1 << offset; 795 | /// Read-only values (empty) 796 | pub mod R {} 797 | /// Write-only values (empty) 798 | pub mod W {} 799 | /// Read-write values 800 | pub mod RW { 801 | 802 | /// 0b0: Address/Data non-multiplexed 803 | pub const Disabled: u32 = 0b0; 804 | 805 | /// 0b1: Address/Data multiplexed on databus 806 | pub const Enabled: u32 = 0b1; 807 | } 808 | } 809 | 810 | /// MBKEN 811 | pub mod MBKEN { 812 | /// Offset (0 bits) 813 | pub const offset: u32 = 0; 814 | /// Mask (1 bit: 1 << 0) 815 | pub const mask: u32 = 1 << offset; 816 | /// Read-only values (empty) 817 | pub mod R {} 818 | /// Write-only values (empty) 819 | pub mod W {} 820 | /// Read-write values 821 | pub mod RW { 822 | 823 | /// 0b0: Corresponding memory bank is disabled 824 | pub const Disabled: u32 = 0b0; 825 | 826 | /// 0b1: Corresponding memory bank is enabled 827 | pub const Enabled: u32 = 0b1; 828 | } 829 | } 830 | 831 | /// CRAM page size 832 | pub mod CPSIZE { 833 | /// Offset (16 bits) 834 | pub const offset: u32 = 16; 835 | /// Mask (3 bits: 0b111 << 16) 836 | pub const mask: u32 = 0b111 << offset; 837 | /// Read-only values (empty) 838 | pub mod R {} 839 | /// Write-only values (empty) 840 | pub mod W {} 841 | /// Read-write values 842 | pub mod RW { 843 | 844 | /// 0b000: No burst split when crossing page boundary 845 | pub const NoBurstSplit: u32 = 0b000; 846 | 847 | /// 0b001: 128 bytes CRAM page size 848 | pub const Bytes128: u32 = 0b001; 849 | 850 | /// 0b010: 256 bytes CRAM page size 851 | pub const Bytes256: u32 = 0b010; 852 | 853 | /// 0b011: 512 bytes CRAM page size 854 | pub const Bytes512: u32 = 0b011; 855 | 856 | /// 0b100: 1024 bytes CRAM page size 857 | pub const Bytes1024: u32 = 0b100; 858 | } 859 | } 860 | } 861 | 862 | /// SRAM/NOR-Flash chip-select control register 2 863 | pub mod BCR3 { 864 | pub use super::BCR2::ASYNCWAIT; 865 | pub use super::BCR2::BURSTEN; 866 | pub use super::BCR2::CBURSTRW; 867 | pub use super::BCR2::CPSIZE; 868 | pub use super::BCR2::EXTMOD; 869 | pub use super::BCR2::FACCEN; 870 | pub use super::BCR2::MBKEN; 871 | pub use super::BCR2::MTYP; 872 | pub use super::BCR2::MUXEN; 873 | pub use super::BCR2::MWID; 874 | pub use super::BCR2::WAITCFG; 875 | pub use super::BCR2::WAITEN; 876 | pub use super::BCR2::WAITPOL; 877 | pub use super::BCR2::WRAPMOD; 878 | pub use super::BCR2::WREN; 879 | } 880 | 881 | /// SRAM/NOR-Flash chip-select control register 2 882 | pub mod BCR4 { 883 | pub use super::BCR2::ASYNCWAIT; 884 | pub use super::BCR2::BURSTEN; 885 | pub use super::BCR2::CBURSTRW; 886 | pub use super::BCR2::CPSIZE; 887 | pub use super::BCR2::EXTMOD; 888 | pub use super::BCR2::FACCEN; 889 | pub use super::BCR2::MBKEN; 890 | pub use super::BCR2::MTYP; 891 | pub use super::BCR2::MUXEN; 892 | pub use super::BCR2::MWID; 893 | pub use super::BCR2::WAITCFG; 894 | pub use super::BCR2::WAITEN; 895 | pub use super::BCR2::WAITPOL; 896 | pub use super::BCR2::WRAPMOD; 897 | pub use super::BCR2::WREN; 898 | } 899 | 900 | /// PC Card/NAND Flash control register 901 | pub mod PCR { 902 | 903 | /// ECCPS 904 | pub mod ECCPS { 905 | /// Offset (17 bits) 906 | pub const offset: u32 = 17; 907 | /// Mask (3 bits: 0b111 << 17) 908 | pub const mask: u32 = 0b111 << offset; 909 | /// Read-only values (empty) 910 | pub mod R {} 911 | /// Write-only values (empty) 912 | pub mod W {} 913 | /// Read-write values 914 | pub mod RW { 915 | 916 | /// 0b000: ECC page size 256 bytes 917 | pub const Bytes256: u32 = 0b000; 918 | 919 | /// 0b001: ECC page size 512 bytes 920 | pub const Bytes512: u32 = 0b001; 921 | 922 | /// 0b010: ECC page size 1024 bytes 923 | pub const Bytes1024: u32 = 0b010; 924 | 925 | /// 0b011: ECC page size 2048 bytes 926 | pub const Bytes2048: u32 = 0b011; 927 | 928 | /// 0b100: ECC page size 4096 bytes 929 | pub const Bytes4096: u32 = 0b100; 930 | 931 | /// 0b101: ECC page size 8192 bytes 932 | pub const Bytes8192: u32 = 0b101; 933 | } 934 | } 935 | 936 | /// TAR 937 | pub mod TAR { 938 | /// Offset (13 bits) 939 | pub const offset: u32 = 13; 940 | /// Mask (4 bits: 0b1111 << 13) 941 | pub const mask: u32 = 0b1111 << offset; 942 | /// Read-only values (empty) 943 | pub mod R {} 944 | /// Write-only values (empty) 945 | pub mod W {} 946 | /// Read-write values (empty) 947 | pub mod RW {} 948 | } 949 | 950 | /// TCLR 951 | pub mod TCLR { 952 | /// Offset (9 bits) 953 | pub const offset: u32 = 9; 954 | /// Mask (4 bits: 0b1111 << 9) 955 | pub const mask: u32 = 0b1111 << offset; 956 | /// Read-only values (empty) 957 | pub mod R {} 958 | /// Write-only values (empty) 959 | pub mod W {} 960 | /// Read-write values (empty) 961 | pub mod RW {} 962 | } 963 | 964 | /// ECCEN 965 | pub mod ECCEN { 966 | /// Offset (6 bits) 967 | pub const offset: u32 = 6; 968 | /// Mask (1 bit: 1 << 6) 969 | pub const mask: u32 = 1 << offset; 970 | /// Read-only values (empty) 971 | pub mod R {} 972 | /// Write-only values (empty) 973 | pub mod W {} 974 | /// Read-write values 975 | pub mod RW { 976 | 977 | /// 0b0: ECC logic is disabled and reset 978 | pub const Disabled: u32 = 0b0; 979 | 980 | /// 0b1: ECC logic is enabled 981 | pub const Enabled: u32 = 0b1; 982 | } 983 | } 984 | 985 | /// PWID 986 | pub mod PWID { 987 | /// Offset (4 bits) 988 | pub const offset: u32 = 4; 989 | /// Mask (2 bits: 0b11 << 4) 990 | pub const mask: u32 = 0b11 << offset; 991 | /// Read-only values (empty) 992 | pub mod R {} 993 | /// Write-only values (empty) 994 | pub mod W {} 995 | /// Read-write values 996 | pub mod RW { 997 | 998 | /// 0b00: External memory device width 8 bits 999 | pub const Bits8: u32 = 0b00; 1000 | 1001 | /// 0b01: External memory device width 16 bits 1002 | pub const Bits16: u32 = 0b01; 1003 | } 1004 | } 1005 | 1006 | /// PTYP 1007 | pub mod PTYP { 1008 | /// Offset (3 bits) 1009 | pub const offset: u32 = 3; 1010 | /// Mask (1 bit: 1 << 3) 1011 | pub const mask: u32 = 1 << offset; 1012 | /// Read-only values (empty) 1013 | pub mod R {} 1014 | /// Write-only values (empty) 1015 | pub mod W {} 1016 | /// Read-write values 1017 | pub mod RW { 1018 | 1019 | /// 0b1: NAND Flash 1020 | pub const NANDFlash: u32 = 0b1; 1021 | } 1022 | } 1023 | 1024 | /// PBKEN 1025 | pub mod PBKEN { 1026 | /// Offset (2 bits) 1027 | pub const offset: u32 = 2; 1028 | /// Mask (1 bit: 1 << 2) 1029 | pub const mask: u32 = 1 << offset; 1030 | /// Read-only values (empty) 1031 | pub mod R {} 1032 | /// Write-only values (empty) 1033 | pub mod W {} 1034 | /// Read-write values 1035 | pub mod RW { 1036 | 1037 | /// 0b0: Corresponding memory bank is disabled 1038 | pub const Disabled: u32 = 0b0; 1039 | 1040 | /// 0b1: Corresponding memory bank is enabled 1041 | pub const Enabled: u32 = 0b1; 1042 | } 1043 | } 1044 | 1045 | /// PWAITEN 1046 | pub mod PWAITEN { 1047 | /// Offset (1 bits) 1048 | pub const offset: u32 = 1; 1049 | /// Mask (1 bit: 1 << 1) 1050 | pub const mask: u32 = 1 << offset; 1051 | /// Read-only values (empty) 1052 | pub mod R {} 1053 | /// Write-only values (empty) 1054 | pub mod W {} 1055 | /// Read-write values 1056 | pub mod RW { 1057 | 1058 | /// 0b0: Wait feature disabled 1059 | pub const Disabled: u32 = 0b0; 1060 | 1061 | /// 0b1: Wait feature enabled 1062 | pub const Enabled: u32 = 0b1; 1063 | } 1064 | } 1065 | } 1066 | 1067 | /// FIFO status and interrupt register 1068 | pub mod SR { 1069 | 1070 | /// FEMPT 1071 | pub mod FEMPT { 1072 | /// Offset (6 bits) 1073 | pub const offset: u32 = 6; 1074 | /// Mask (1 bit: 1 << 6) 1075 | pub const mask: u32 = 1 << offset; 1076 | /// Read-only values (empty) 1077 | pub mod R {} 1078 | /// Write-only values (empty) 1079 | pub mod W {} 1080 | /// Read-write values 1081 | pub mod RW { 1082 | 1083 | /// 0b0: FIFO not empty 1084 | pub const NotEmpty: u32 = 0b0; 1085 | 1086 | /// 0b1: FIFO empty 1087 | pub const Empty: u32 = 0b1; 1088 | } 1089 | } 1090 | 1091 | /// IFEN 1092 | pub mod IFEN { 1093 | /// Offset (5 bits) 1094 | pub const offset: u32 = 5; 1095 | /// Mask (1 bit: 1 << 5) 1096 | pub const mask: u32 = 1 << offset; 1097 | /// Read-only values (empty) 1098 | pub mod R {} 1099 | /// Write-only values (empty) 1100 | pub mod W {} 1101 | /// Read-write values 1102 | pub mod RW { 1103 | 1104 | /// 0b0: Interrupt falling edge detection request disabled 1105 | pub const Disabled: u32 = 0b0; 1106 | 1107 | /// 0b1: Interrupt falling edge detection request enabled 1108 | pub const Enabled: u32 = 0b1; 1109 | } 1110 | } 1111 | 1112 | /// ILEN 1113 | pub mod ILEN { 1114 | /// Offset (4 bits) 1115 | pub const offset: u32 = 4; 1116 | /// Mask (1 bit: 1 << 4) 1117 | pub const mask: u32 = 1 << offset; 1118 | /// Read-only values (empty) 1119 | pub mod R {} 1120 | /// Write-only values (empty) 1121 | pub mod W {} 1122 | /// Read-write values 1123 | pub mod RW { 1124 | 1125 | /// 0b0: Interrupt high-level detection request disabled 1126 | pub const Disabled: u32 = 0b0; 1127 | 1128 | /// 0b1: Interrupt high-level detection request enabled 1129 | pub const Enabled: u32 = 0b1; 1130 | } 1131 | } 1132 | 1133 | /// IREN 1134 | pub mod IREN { 1135 | /// Offset (3 bits) 1136 | pub const offset: u32 = 3; 1137 | /// Mask (1 bit: 1 << 3) 1138 | pub const mask: u32 = 1 << offset; 1139 | /// Read-only values (empty) 1140 | pub mod R {} 1141 | /// Write-only values (empty) 1142 | pub mod W {} 1143 | /// Read-write values 1144 | pub mod RW { 1145 | 1146 | /// 0b0: Interrupt rising edge detection request disabled 1147 | pub const Disabled: u32 = 0b0; 1148 | 1149 | /// 0b1: Interrupt rising edge detection request enabled 1150 | pub const Enabled: u32 = 0b1; 1151 | } 1152 | } 1153 | 1154 | /// IFS 1155 | pub mod IFS { 1156 | /// Offset (2 bits) 1157 | pub const offset: u32 = 2; 1158 | /// Mask (1 bit: 1 << 2) 1159 | pub const mask: u32 = 1 << offset; 1160 | /// Read-only values (empty) 1161 | pub mod R {} 1162 | /// Write-only values (empty) 1163 | pub mod W {} 1164 | /// Read-write values 1165 | pub mod RW { 1166 | 1167 | /// 0b0: Interrupt falling edge did not occur 1168 | pub const DidNotOccur: u32 = 0b0; 1169 | 1170 | /// 0b1: Interrupt falling edge occurred 1171 | pub const Occurred: u32 = 0b1; 1172 | } 1173 | } 1174 | 1175 | /// ILS 1176 | pub mod ILS { 1177 | /// Offset (1 bits) 1178 | pub const offset: u32 = 1; 1179 | /// Mask (1 bit: 1 << 1) 1180 | pub const mask: u32 = 1 << offset; 1181 | /// Read-only values (empty) 1182 | pub mod R {} 1183 | /// Write-only values (empty) 1184 | pub mod W {} 1185 | /// Read-write values 1186 | pub mod RW { 1187 | 1188 | /// 0b0: Interrupt high-level did not occur 1189 | pub const DidNotOccur: u32 = 0b0; 1190 | 1191 | /// 0b1: Interrupt high-level occurred 1192 | pub const Occurred: u32 = 0b1; 1193 | } 1194 | } 1195 | 1196 | /// IRS 1197 | pub mod IRS { 1198 | /// Offset (0 bits) 1199 | pub const offset: u32 = 0; 1200 | /// Mask (1 bit: 1 << 0) 1201 | pub const mask: u32 = 1 << offset; 1202 | /// Read-only values (empty) 1203 | pub mod R {} 1204 | /// Write-only values (empty) 1205 | pub mod W {} 1206 | /// Read-write values 1207 | pub mod RW { 1208 | 1209 | /// 0b0: Interrupt rising edge did not occur 1210 | pub const DidNotOccur: u32 = 0b0; 1211 | 1212 | /// 0b1: Interrupt rising edge occurred 1213 | pub const Occurred: u32 = 0b1; 1214 | } 1215 | } 1216 | } 1217 | 1218 | /// Common memory space timing register 1219 | pub mod PMEM { 1220 | 1221 | /// MEMHIZx 1222 | pub mod MEMHIZ { 1223 | /// Offset (24 bits) 1224 | pub const offset: u32 = 24; 1225 | /// Mask (8 bits: 0xff << 24) 1226 | pub const mask: u32 = 0xff << offset; 1227 | /// Read-only values (empty) 1228 | pub mod R {} 1229 | /// Write-only values (empty) 1230 | pub mod W {} 1231 | /// Read-write values (empty) 1232 | pub mod RW {} 1233 | } 1234 | 1235 | /// MEMHOLDx 1236 | pub mod MEMHOLD { 1237 | /// Offset (16 bits) 1238 | pub const offset: u32 = 16; 1239 | /// Mask (8 bits: 0xff << 16) 1240 | pub const mask: u32 = 0xff << offset; 1241 | /// Read-only values (empty) 1242 | pub mod R {} 1243 | /// Write-only values (empty) 1244 | pub mod W {} 1245 | /// Read-write values (empty) 1246 | pub mod RW {} 1247 | } 1248 | 1249 | /// MEMWAITx 1250 | pub mod MEMWAIT { 1251 | /// Offset (8 bits) 1252 | pub const offset: u32 = 8; 1253 | /// Mask (8 bits: 0xff << 8) 1254 | pub const mask: u32 = 0xff << offset; 1255 | /// Read-only values (empty) 1256 | pub mod R {} 1257 | /// Write-only values (empty) 1258 | pub mod W {} 1259 | /// Read-write values (empty) 1260 | pub mod RW {} 1261 | } 1262 | 1263 | /// MEMSETx 1264 | pub mod MEMSET { 1265 | /// Offset (0 bits) 1266 | pub const offset: u32 = 0; 1267 | /// Mask (8 bits: 0xff << 0) 1268 | pub const mask: u32 = 0xff << offset; 1269 | /// Read-only values (empty) 1270 | pub mod R {} 1271 | /// Write-only values (empty) 1272 | pub mod W {} 1273 | /// Read-write values (empty) 1274 | pub mod RW {} 1275 | } 1276 | } 1277 | 1278 | /// Attribute memory space timing register 1279 | pub mod PATT { 1280 | 1281 | /// ATTHIZx 1282 | pub mod ATTHIZ { 1283 | /// Offset (24 bits) 1284 | pub const offset: u32 = 24; 1285 | /// Mask (8 bits: 0xff << 24) 1286 | pub const mask: u32 = 0xff << offset; 1287 | /// Read-only values (empty) 1288 | pub mod R {} 1289 | /// Write-only values (empty) 1290 | pub mod W {} 1291 | /// Read-write values (empty) 1292 | pub mod RW {} 1293 | } 1294 | 1295 | /// ATTHOLDx 1296 | pub mod ATTHOLD { 1297 | /// Offset (16 bits) 1298 | pub const offset: u32 = 16; 1299 | /// Mask (8 bits: 0xff << 16) 1300 | pub const mask: u32 = 0xff << offset; 1301 | /// Read-only values (empty) 1302 | pub mod R {} 1303 | /// Write-only values (empty) 1304 | pub mod W {} 1305 | /// Read-write values (empty) 1306 | pub mod RW {} 1307 | } 1308 | 1309 | /// ATTWAITx 1310 | pub mod ATTWAIT { 1311 | /// Offset (8 bits) 1312 | pub const offset: u32 = 8; 1313 | /// Mask (8 bits: 0xff << 8) 1314 | pub const mask: u32 = 0xff << offset; 1315 | /// Read-only values (empty) 1316 | pub mod R {} 1317 | /// Write-only values (empty) 1318 | pub mod W {} 1319 | /// Read-write values (empty) 1320 | pub mod RW {} 1321 | } 1322 | 1323 | /// ATTSETx 1324 | pub mod ATTSET { 1325 | /// Offset (0 bits) 1326 | pub const offset: u32 = 0; 1327 | /// Mask (8 bits: 0xff << 0) 1328 | pub const mask: u32 = 0xff << offset; 1329 | /// Read-only values (empty) 1330 | pub mod R {} 1331 | /// Write-only values (empty) 1332 | pub mod W {} 1333 | /// Read-write values (empty) 1334 | pub mod RW {} 1335 | } 1336 | } 1337 | 1338 | /// ECC result register 1339 | pub mod ECCR { 1340 | 1341 | /// ECCx 1342 | pub mod ECC { 1343 | /// Offset (0 bits) 1344 | pub const offset: u32 = 0; 1345 | /// Mask (32 bits: 0xffffffff << 0) 1346 | pub const mask: u32 = 0xffffffff << offset; 1347 | /// Read-only values (empty) 1348 | pub mod R {} 1349 | /// Write-only values (empty) 1350 | pub mod W {} 1351 | /// Read-write values (empty) 1352 | pub mod RW {} 1353 | } 1354 | } 1355 | 1356 | /// SRAM/NOR-Flash write timing registers 1 1357 | pub mod BWTR1 { 1358 | 1359 | /// ACCMOD 1360 | pub mod ACCMOD { 1361 | /// Offset (28 bits) 1362 | pub const offset: u32 = 28; 1363 | /// Mask (2 bits: 0b11 << 28) 1364 | pub const mask: u32 = 0b11 << offset; 1365 | /// Read-only values (empty) 1366 | pub mod R {} 1367 | /// Write-only values (empty) 1368 | pub mod W {} 1369 | /// Read-write values 1370 | pub mod RW { 1371 | 1372 | /// 0b00: Access mode A 1373 | pub const A: u32 = 0b00; 1374 | 1375 | /// 0b01: Access mode B 1376 | pub const B: u32 = 0b01; 1377 | 1378 | /// 0b10: Access mode C 1379 | pub const C: u32 = 0b10; 1380 | 1381 | /// 0b11: Access mode D 1382 | pub const D: u32 = 0b11; 1383 | } 1384 | } 1385 | 1386 | /// CLKDIV 1387 | pub mod CLKDIV { 1388 | /// Offset (20 bits) 1389 | pub const offset: u32 = 20; 1390 | /// Mask (4 bits: 0b1111 << 20) 1391 | pub const mask: u32 = 0b1111 << offset; 1392 | /// Read-only values (empty) 1393 | pub mod R {} 1394 | /// Write-only values (empty) 1395 | pub mod W {} 1396 | /// Read-write values (empty) 1397 | pub mod RW {} 1398 | } 1399 | 1400 | /// DATAST 1401 | pub mod DATAST { 1402 | /// Offset (8 bits) 1403 | pub const offset: u32 = 8; 1404 | /// Mask (8 bits: 0xff << 8) 1405 | pub const mask: u32 = 0xff << offset; 1406 | /// Read-only values (empty) 1407 | pub mod R {} 1408 | /// Write-only values (empty) 1409 | pub mod W {} 1410 | /// Read-write values (empty) 1411 | pub mod RW {} 1412 | } 1413 | 1414 | /// ADDHLD 1415 | pub mod ADDHLD { 1416 | /// Offset (4 bits) 1417 | pub const offset: u32 = 4; 1418 | /// Mask (4 bits: 0b1111 << 4) 1419 | pub const mask: u32 = 0b1111 << offset; 1420 | /// Read-only values (empty) 1421 | pub mod R {} 1422 | /// Write-only values (empty) 1423 | pub mod W {} 1424 | /// Read-write values (empty) 1425 | pub mod RW {} 1426 | } 1427 | 1428 | /// ADDSET 1429 | pub mod ADDSET { 1430 | /// Offset (0 bits) 1431 | pub const offset: u32 = 0; 1432 | /// Mask (4 bits: 0b1111 << 0) 1433 | pub const mask: u32 = 0b1111 << offset; 1434 | /// Read-only values (empty) 1435 | pub mod R {} 1436 | /// Write-only values (empty) 1437 | pub mod W {} 1438 | /// Read-write values (empty) 1439 | pub mod RW {} 1440 | } 1441 | 1442 | /// Bus turnaround phase duration 1443 | pub mod BUSTURN { 1444 | /// Offset (16 bits) 1445 | pub const offset: u32 = 16; 1446 | /// Mask (4 bits: 0b1111 << 16) 1447 | pub const mask: u32 = 0b1111 << offset; 1448 | /// Read-only values (empty) 1449 | pub mod R {} 1450 | /// Write-only values (empty) 1451 | pub mod W {} 1452 | /// Read-write values (empty) 1453 | pub mod RW {} 1454 | } 1455 | } 1456 | 1457 | /// SRAM/NOR-Flash write timing registers 1 1458 | pub mod BWTR2 { 1459 | pub use super::BWTR1::ACCMOD; 1460 | pub use super::BWTR1::ADDHLD; 1461 | pub use super::BWTR1::ADDSET; 1462 | pub use super::BWTR1::BUSTURN; 1463 | pub use super::BWTR1::CLKDIV; 1464 | pub use super::BWTR1::DATAST; 1465 | } 1466 | 1467 | /// SRAM/NOR-Flash write timing registers 1 1468 | pub mod BWTR3 { 1469 | pub use super::BWTR1::ACCMOD; 1470 | pub use super::BWTR1::ADDHLD; 1471 | pub use super::BWTR1::ADDSET; 1472 | pub use super::BWTR1::BUSTURN; 1473 | pub use super::BWTR1::CLKDIV; 1474 | pub use super::BWTR1::DATAST; 1475 | } 1476 | 1477 | /// SRAM/NOR-Flash write timing registers 1 1478 | pub mod BWTR4 { 1479 | pub use super::BWTR1::ACCMOD; 1480 | pub use super::BWTR1::ADDHLD; 1481 | pub use super::BWTR1::ADDSET; 1482 | pub use super::BWTR1::BUSTURN; 1483 | pub use super::BWTR1::CLKDIV; 1484 | pub use super::BWTR1::DATAST; 1485 | } 1486 | 1487 | /// SDRAM Control Register 1 1488 | pub mod SDCR1 { 1489 | 1490 | /// Number of column address bits 1491 | pub mod NC { 1492 | /// Offset (0 bits) 1493 | pub const offset: u32 = 0; 1494 | /// Mask (2 bits: 0b11 << 0) 1495 | pub const mask: u32 = 0b11 << offset; 1496 | /// Read-only values (empty) 1497 | pub mod R {} 1498 | /// Write-only values (empty) 1499 | pub mod W {} 1500 | /// Read-write values 1501 | pub mod RW { 1502 | 1503 | /// 0b00: 8 bits 1504 | pub const Bits8: u32 = 0b00; 1505 | 1506 | /// 0b01: 9 bits 1507 | pub const Bits9: u32 = 0b01; 1508 | 1509 | /// 0b10: 10 bits 1510 | pub const Bits10: u32 = 0b10; 1511 | 1512 | /// 0b11: 11 bits 1513 | pub const Bits11: u32 = 0b11; 1514 | } 1515 | } 1516 | 1517 | /// Number of row address bits 1518 | pub mod NR { 1519 | /// Offset (2 bits) 1520 | pub const offset: u32 = 2; 1521 | /// Mask (2 bits: 0b11 << 2) 1522 | pub const mask: u32 = 0b11 << offset; 1523 | /// Read-only values (empty) 1524 | pub mod R {} 1525 | /// Write-only values (empty) 1526 | pub mod W {} 1527 | /// Read-write values 1528 | pub mod RW { 1529 | 1530 | /// 0b00: 11 bits 1531 | pub const Bits11: u32 = 0b00; 1532 | 1533 | /// 0b01: 12 bits 1534 | pub const Bits12: u32 = 0b01; 1535 | 1536 | /// 0b10: 13 bits 1537 | pub const Bits13: u32 = 0b10; 1538 | } 1539 | } 1540 | 1541 | /// Memory data bus width 1542 | pub mod MWID { 1543 | /// Offset (4 bits) 1544 | pub const offset: u32 = 4; 1545 | /// Mask (2 bits: 0b11 << 4) 1546 | pub const mask: u32 = 0b11 << offset; 1547 | /// Read-only values (empty) 1548 | pub mod R {} 1549 | /// Write-only values (empty) 1550 | pub mod W {} 1551 | /// Read-write values 1552 | pub mod RW { 1553 | 1554 | /// 0b00: Memory data bus width 8 bits 1555 | pub const Bits8: u32 = 0b00; 1556 | 1557 | /// 0b01: Memory data bus width 16 bits 1558 | pub const Bits16: u32 = 0b01; 1559 | 1560 | /// 0b10: Memory data bus width 32 bits 1561 | pub const Bits32: u32 = 0b10; 1562 | } 1563 | } 1564 | 1565 | /// Number of internal banks 1566 | pub mod NB { 1567 | /// Offset (6 bits) 1568 | pub const offset: u32 = 6; 1569 | /// Mask (1 bit: 1 << 6) 1570 | pub const mask: u32 = 1 << offset; 1571 | /// Read-only values (empty) 1572 | pub mod R {} 1573 | /// Write-only values (empty) 1574 | pub mod W {} 1575 | /// Read-write values 1576 | pub mod RW { 1577 | 1578 | /// 0b0: Two internal Banks 1579 | pub const NB2: u32 = 0b0; 1580 | 1581 | /// 0b1: Four internal Banks 1582 | pub const NB4: u32 = 0b1; 1583 | } 1584 | } 1585 | 1586 | /// CAS latency 1587 | pub mod CAS { 1588 | /// Offset (7 bits) 1589 | pub const offset: u32 = 7; 1590 | /// Mask (2 bits: 0b11 << 7) 1591 | pub const mask: u32 = 0b11 << offset; 1592 | /// Read-only values (empty) 1593 | pub mod R {} 1594 | /// Write-only values (empty) 1595 | pub mod W {} 1596 | /// Read-write values 1597 | pub mod RW { 1598 | 1599 | /// 0b01: 1 cycle 1600 | pub const Clocks1: u32 = 0b01; 1601 | 1602 | /// 0b10: 2 cycles 1603 | pub const Clocks2: u32 = 0b10; 1604 | 1605 | /// 0b11: 3 cycles 1606 | pub const Clocks3: u32 = 0b11; 1607 | } 1608 | } 1609 | 1610 | /// Write protection 1611 | pub mod WP { 1612 | /// Offset (9 bits) 1613 | pub const offset: u32 = 9; 1614 | /// Mask (1 bit: 1 << 9) 1615 | pub const mask: u32 = 1 << offset; 1616 | /// Read-only values (empty) 1617 | pub mod R {} 1618 | /// Write-only values (empty) 1619 | pub mod W {} 1620 | /// Read-write values 1621 | pub mod RW { 1622 | 1623 | /// 0b0: Write accesses allowed 1624 | pub const Disabled: u32 = 0b0; 1625 | 1626 | /// 0b1: Write accesses ignored 1627 | pub const Enabled: u32 = 0b1; 1628 | } 1629 | } 1630 | 1631 | /// SDRAM clock configuration 1632 | pub mod SDCLK { 1633 | /// Offset (10 bits) 1634 | pub const offset: u32 = 10; 1635 | /// Mask (2 bits: 0b11 << 10) 1636 | pub const mask: u32 = 0b11 << offset; 1637 | /// Read-only values (empty) 1638 | pub mod R {} 1639 | /// Write-only values (empty) 1640 | pub mod W {} 1641 | /// Read-write values 1642 | pub mod RW { 1643 | 1644 | /// 0b00: SDCLK clock disabled 1645 | pub const Disabled: u32 = 0b00; 1646 | 1647 | /// 0b10: SDCLK period = 2 x HCLK period 1648 | pub const Div2: u32 = 0b10; 1649 | 1650 | /// 0b11: SDCLK period = 3 x HCLK period 1651 | pub const Div3: u32 = 0b11; 1652 | } 1653 | } 1654 | 1655 | /// Burst read 1656 | pub mod RBURST { 1657 | /// Offset (12 bits) 1658 | pub const offset: u32 = 12; 1659 | /// Mask (1 bit: 1 << 12) 1660 | pub const mask: u32 = 1 << offset; 1661 | /// Read-only values (empty) 1662 | pub mod R {} 1663 | /// Write-only values (empty) 1664 | pub mod W {} 1665 | /// Read-write values 1666 | pub mod RW { 1667 | 1668 | /// 0b0: Single read requests are not managed as bursts 1669 | pub const Disabled: u32 = 0b0; 1670 | 1671 | /// 0b1: Single read requests are always managed as bursts 1672 | pub const Enabled: u32 = 0b1; 1673 | } 1674 | } 1675 | 1676 | /// Read pipe 1677 | pub mod RPIPE { 1678 | /// Offset (13 bits) 1679 | pub const offset: u32 = 13; 1680 | /// Mask (2 bits: 0b11 << 13) 1681 | pub const mask: u32 = 0b11 << offset; 1682 | /// Read-only values (empty) 1683 | pub mod R {} 1684 | /// Write-only values (empty) 1685 | pub mod W {} 1686 | /// Read-write values 1687 | pub mod RW { 1688 | 1689 | /// 0b00: No clock cycle delay 1690 | pub const NoDelay: u32 = 0b00; 1691 | 1692 | /// 0b01: One clock cycle delay 1693 | pub const Clocks1: u32 = 0b01; 1694 | 1695 | /// 0b10: Two clock cycles delay 1696 | pub const Clocks2: u32 = 0b10; 1697 | } 1698 | } 1699 | } 1700 | 1701 | /// SDRAM Control Register 1 1702 | pub mod SDCR2 { 1703 | pub use super::SDCR1::CAS; 1704 | pub use super::SDCR1::MWID; 1705 | pub use super::SDCR1::NB; 1706 | pub use super::SDCR1::NC; 1707 | pub use super::SDCR1::NR; 1708 | pub use super::SDCR1::RBURST; 1709 | pub use super::SDCR1::RPIPE; 1710 | pub use super::SDCR1::SDCLK; 1711 | pub use super::SDCR1::WP; 1712 | } 1713 | 1714 | /// SDRAM Timing register 1 1715 | pub mod SDTR1 { 1716 | 1717 | /// Load Mode Register to Active 1718 | pub mod TMRD { 1719 | /// Offset (0 bits) 1720 | pub const offset: u32 = 0; 1721 | /// Mask (4 bits: 0b1111 << 0) 1722 | pub const mask: u32 = 0b1111 << offset; 1723 | /// Read-only values (empty) 1724 | pub mod R {} 1725 | /// Write-only values (empty) 1726 | pub mod W {} 1727 | /// Read-write values (empty) 1728 | pub mod RW {} 1729 | } 1730 | 1731 | /// Exit self-refresh delay 1732 | pub mod TXSR { 1733 | /// Offset (4 bits) 1734 | pub const offset: u32 = 4; 1735 | /// Mask (4 bits: 0b1111 << 4) 1736 | pub const mask: u32 = 0b1111 << offset; 1737 | /// Read-only values (empty) 1738 | pub mod R {} 1739 | /// Write-only values (empty) 1740 | pub mod W {} 1741 | /// Read-write values (empty) 1742 | pub mod RW {} 1743 | } 1744 | 1745 | /// Self refresh time 1746 | pub mod TRAS { 1747 | /// Offset (8 bits) 1748 | pub const offset: u32 = 8; 1749 | /// Mask (4 bits: 0b1111 << 8) 1750 | pub const mask: u32 = 0b1111 << offset; 1751 | /// Read-only values (empty) 1752 | pub mod R {} 1753 | /// Write-only values (empty) 1754 | pub mod W {} 1755 | /// Read-write values (empty) 1756 | pub mod RW {} 1757 | } 1758 | 1759 | /// Row cycle delay 1760 | pub mod TRC { 1761 | /// Offset (12 bits) 1762 | pub const offset: u32 = 12; 1763 | /// Mask (4 bits: 0b1111 << 12) 1764 | pub const mask: u32 = 0b1111 << offset; 1765 | /// Read-only values (empty) 1766 | pub mod R {} 1767 | /// Write-only values (empty) 1768 | pub mod W {} 1769 | /// Read-write values (empty) 1770 | pub mod RW {} 1771 | } 1772 | 1773 | /// Recovery delay 1774 | pub mod TWR { 1775 | /// Offset (16 bits) 1776 | pub const offset: u32 = 16; 1777 | /// Mask (4 bits: 0b1111 << 16) 1778 | pub const mask: u32 = 0b1111 << offset; 1779 | /// Read-only values (empty) 1780 | pub mod R {} 1781 | /// Write-only values (empty) 1782 | pub mod W {} 1783 | /// Read-write values (empty) 1784 | pub mod RW {} 1785 | } 1786 | 1787 | /// Row precharge delay 1788 | pub mod TRP { 1789 | /// Offset (20 bits) 1790 | pub const offset: u32 = 20; 1791 | /// Mask (4 bits: 0b1111 << 20) 1792 | pub const mask: u32 = 0b1111 << offset; 1793 | /// Read-only values (empty) 1794 | pub mod R {} 1795 | /// Write-only values (empty) 1796 | pub mod W {} 1797 | /// Read-write values (empty) 1798 | pub mod RW {} 1799 | } 1800 | 1801 | /// Row to column delay 1802 | pub mod TRCD { 1803 | /// Offset (24 bits) 1804 | pub const offset: u32 = 24; 1805 | /// Mask (4 bits: 0b1111 << 24) 1806 | pub const mask: u32 = 0b1111 << offset; 1807 | /// Read-only values (empty) 1808 | pub mod R {} 1809 | /// Write-only values (empty) 1810 | pub mod W {} 1811 | /// Read-write values (empty) 1812 | pub mod RW {} 1813 | } 1814 | } 1815 | 1816 | /// SDRAM Timing register 1 1817 | pub mod SDTR2 { 1818 | pub use super::SDTR1::TMRD; 1819 | pub use super::SDTR1::TRAS; 1820 | pub use super::SDTR1::TRC; 1821 | pub use super::SDTR1::TRCD; 1822 | pub use super::SDTR1::TRP; 1823 | pub use super::SDTR1::TWR; 1824 | pub use super::SDTR1::TXSR; 1825 | } 1826 | 1827 | /// SDRAM Command Mode register 1828 | pub mod SDCMR { 1829 | 1830 | /// Command mode 1831 | pub mod MODE { 1832 | /// Offset (0 bits) 1833 | pub const offset: u32 = 0; 1834 | /// Mask (3 bits: 0b111 << 0) 1835 | pub const mask: u32 = 0b111 << offset; 1836 | /// Read-only values (empty) 1837 | pub mod R {} 1838 | /// Write-only values (empty) 1839 | pub mod W {} 1840 | /// Read-write values 1841 | pub mod RW { 1842 | 1843 | /// 0b000: Normal Mode 1844 | pub const Normal: u32 = 0b000; 1845 | 1846 | /// 0b001: Clock Configuration Enable 1847 | pub const ClockConfigurationEnable: u32 = 0b001; 1848 | 1849 | /// 0b010: PALL (All Bank Precharge) command 1850 | pub const PALL: u32 = 0b010; 1851 | 1852 | /// 0b011: Auto-refresh command 1853 | pub const AutoRefreshCommand: u32 = 0b011; 1854 | 1855 | /// 0b100: Load Mode Resgier 1856 | pub const LoadModeRegister: u32 = 0b100; 1857 | 1858 | /// 0b101: Self-refresh command 1859 | pub const SelfRefreshCommand: u32 = 0b101; 1860 | 1861 | /// 0b110: Power-down command 1862 | pub const PowerDownCommand: u32 = 0b110; 1863 | } 1864 | } 1865 | 1866 | /// Command target bank 2 1867 | pub mod CTB2 { 1868 | /// Offset (3 bits) 1869 | pub const offset: u32 = 3; 1870 | /// Mask (1 bit: 1 << 3) 1871 | pub const mask: u32 = 1 << offset; 1872 | /// Read-only values (empty) 1873 | pub mod R {} 1874 | /// Write-only values (empty) 1875 | pub mod W {} 1876 | /// Read-write values 1877 | pub mod RW { 1878 | 1879 | /// 0b0: Command not issued to SDRAM Bank 1 1880 | pub const NotIssued: u32 = 0b0; 1881 | 1882 | /// 0b1: Command issued to SDRAM Bank 1 1883 | pub const Issued: u32 = 0b1; 1884 | } 1885 | } 1886 | 1887 | /// Command target bank 1 1888 | pub mod CTB1 { 1889 | /// Offset (4 bits) 1890 | pub const offset: u32 = 4; 1891 | /// Mask (1 bit: 1 << 4) 1892 | pub const mask: u32 = 1 << offset; 1893 | /// Read-only values (empty) 1894 | pub mod R {} 1895 | /// Write-only values (empty) 1896 | pub mod W {} 1897 | pub use super::CTB2::RW; 1898 | } 1899 | 1900 | /// Number of Auto-refresh 1901 | pub mod NRFS { 1902 | /// Offset (5 bits) 1903 | pub const offset: u32 = 5; 1904 | /// Mask (4 bits: 0b1111 << 5) 1905 | pub const mask: u32 = 0b1111 << offset; 1906 | /// Read-only values (empty) 1907 | pub mod R {} 1908 | /// Write-only values (empty) 1909 | pub mod W {} 1910 | /// Read-write values (empty) 1911 | pub mod RW {} 1912 | } 1913 | 1914 | /// Mode Register definition 1915 | pub mod MRD { 1916 | /// Offset (9 bits) 1917 | pub const offset: u32 = 9; 1918 | /// Mask (14 bits: 0x3fff << 9) 1919 | pub const mask: u32 = 0x3fff << offset; 1920 | /// Read-only values (empty) 1921 | pub mod R {} 1922 | /// Write-only values (empty) 1923 | pub mod W {} 1924 | /// Read-write values (empty) 1925 | pub mod RW {} 1926 | } 1927 | } 1928 | 1929 | /// SDRAM Refresh Timer register 1930 | pub mod SDRTR { 1931 | 1932 | /// Clear Refresh error flag 1933 | pub mod CRE { 1934 | /// Offset (0 bits) 1935 | pub const offset: u32 = 0; 1936 | /// Mask (1 bit: 1 << 0) 1937 | pub const mask: u32 = 1 << offset; 1938 | /// Read-only values (empty) 1939 | pub mod R {} 1940 | /// Write-only values (empty) 1941 | pub mod W {} 1942 | /// Read-write values 1943 | pub mod RW { 1944 | 1945 | /// 0b1: Refresh Error Flag is cleared 1946 | pub const Clear: u32 = 0b1; 1947 | } 1948 | } 1949 | 1950 | /// Refresh Timer Count 1951 | pub mod COUNT { 1952 | /// Offset (1 bits) 1953 | pub const offset: u32 = 1; 1954 | /// Mask (13 bits: 0x1fff << 1) 1955 | pub const mask: u32 = 0x1fff << offset; 1956 | /// Read-only values (empty) 1957 | pub mod R {} 1958 | /// Write-only values (empty) 1959 | pub mod W {} 1960 | /// Read-write values (empty) 1961 | pub mod RW {} 1962 | } 1963 | 1964 | /// RES Interrupt Enable 1965 | pub mod REIE { 1966 | /// Offset (14 bits) 1967 | pub const offset: u32 = 14; 1968 | /// Mask (1 bit: 1 << 14) 1969 | pub const mask: u32 = 1 << offset; 1970 | /// Read-only values (empty) 1971 | pub mod R {} 1972 | /// Write-only values (empty) 1973 | pub mod W {} 1974 | /// Read-write values 1975 | pub mod RW { 1976 | 1977 | /// 0b0: Interrupt is disabled 1978 | pub const Disabled: u32 = 0b0; 1979 | 1980 | /// 0b1: Interrupt is generated if RE = 1 1981 | pub const Enabled: u32 = 0b1; 1982 | } 1983 | } 1984 | } 1985 | 1986 | /// SDRAM Status register 1987 | pub mod SDSR { 1988 | 1989 | /// Refresh error flag 1990 | pub mod RE { 1991 | /// Offset (0 bits) 1992 | pub const offset: u32 = 0; 1993 | /// Mask (1 bit: 1 << 0) 1994 | pub const mask: u32 = 1 << offset; 1995 | /// Read-only values (empty) 1996 | pub mod R {} 1997 | /// Write-only values (empty) 1998 | pub mod W {} 1999 | /// Read-write values 2000 | pub mod RW { 2001 | 2002 | /// 0b0: No refresh error has been detected 2003 | pub const NoError: u32 = 0b0; 2004 | 2005 | /// 0b1: A refresh error has been detected 2006 | pub const Error: u32 = 0b1; 2007 | } 2008 | } 2009 | 2010 | /// Status Mode for Bank 1 2011 | pub mod MODES1 { 2012 | /// Offset (1 bits) 2013 | pub const offset: u32 = 1; 2014 | /// Mask (2 bits: 0b11 << 1) 2015 | pub const mask: u32 = 0b11 << offset; 2016 | /// Read-only values (empty) 2017 | pub mod R {} 2018 | /// Write-only values (empty) 2019 | pub mod W {} 2020 | /// Read-write values 2021 | pub mod RW { 2022 | 2023 | /// 0b00: Normal Mode 2024 | pub const Normal: u32 = 0b00; 2025 | 2026 | /// 0b01: Self-refresh mode 2027 | pub const SelfRefresh: u32 = 0b01; 2028 | 2029 | /// 0b10: Power-down mode 2030 | pub const PowerDown: u32 = 0b10; 2031 | } 2032 | } 2033 | 2034 | /// Status Mode for Bank 2 2035 | pub mod MODES2 { 2036 | /// Offset (3 bits) 2037 | pub const offset: u32 = 3; 2038 | /// Mask (2 bits: 0b11 << 3) 2039 | pub const mask: u32 = 0b11 << offset; 2040 | /// Read-only values (empty) 2041 | pub mod R {} 2042 | /// Write-only values (empty) 2043 | pub mod W {} 2044 | pub use super::MODES1::RW; 2045 | } 2046 | 2047 | /// Busy status 2048 | pub mod BUSY { 2049 | /// Offset (5 bits) 2050 | pub const offset: u32 = 5; 2051 | /// Mask (1 bit: 1 << 5) 2052 | pub const mask: u32 = 1 << offset; 2053 | /// Read-only values (empty) 2054 | pub mod R {} 2055 | /// Write-only values (empty) 2056 | pub mod W {} 2057 | /// Read-write values 2058 | pub mod RW { 2059 | 2060 | /// 0b0: SDRAM Controller is ready to accept a new request 2061 | pub const NotBusy: u32 = 0b0; 2062 | 2063 | /// 0b1: SDRAM Controller is not ready to accept a new request 2064 | pub const Busy: u32 = 0b1; 2065 | } 2066 | } 2067 | } 2068 | #[repr(C)] 2069 | pub struct RegisterBlock { 2070 | /// SRAM/NOR-Flash chip-select control register 1 2071 | pub BCR1: RWRegister, 2072 | 2073 | /// SRAM/NOR-Flash chip-select timing register 1 2074 | pub BTR1: RWRegister, 2075 | 2076 | /// SRAM/NOR-Flash chip-select control register 2 2077 | pub BCR2: RWRegister, 2078 | 2079 | /// SRAM/NOR-Flash chip-select timing register 1 2080 | pub BTR2: RWRegister, 2081 | 2082 | /// SRAM/NOR-Flash chip-select control register 2 2083 | pub BCR3: RWRegister, 2084 | 2085 | /// SRAM/NOR-Flash chip-select timing register 1 2086 | pub BTR3: RWRegister, 2087 | 2088 | /// SRAM/NOR-Flash chip-select control register 2 2089 | pub BCR4: RWRegister, 2090 | 2091 | /// SRAM/NOR-Flash chip-select timing register 1 2092 | pub BTR4: RWRegister, 2093 | 2094 | _reserved1: [u32; 24], 2095 | 2096 | /// PC Card/NAND Flash control register 2097 | pub PCR: RWRegister, 2098 | 2099 | /// FIFO status and interrupt register 2100 | pub SR: RWRegister, 2101 | 2102 | /// Common memory space timing register 2103 | pub PMEM: RWRegister, 2104 | 2105 | /// Attribute memory space timing register 2106 | pub PATT: RWRegister, 2107 | 2108 | _reserved2: [u32; 1], 2109 | 2110 | /// ECC result register 2111 | pub ECCR: RORegister, 2112 | 2113 | _reserved3: [u32; 27], 2114 | 2115 | /// SRAM/NOR-Flash write timing registers 1 2116 | pub BWTR1: RWRegister, 2117 | 2118 | _reserved4: [u32; 1], 2119 | 2120 | /// SRAM/NOR-Flash write timing registers 1 2121 | pub BWTR2: RWRegister, 2122 | 2123 | _reserved5: [u32; 1], 2124 | 2125 | /// SRAM/NOR-Flash write timing registers 1 2126 | pub BWTR3: RWRegister, 2127 | 2128 | _reserved6: [u32; 1], 2129 | 2130 | /// SRAM/NOR-Flash write timing registers 1 2131 | pub BWTR4: RWRegister, 2132 | 2133 | _reserved7: [u32; 8], 2134 | 2135 | /// SDRAM Control Register 1 2136 | pub SDCR1: RWRegister, 2137 | 2138 | /// SDRAM Control Register 1 2139 | pub SDCR2: RWRegister, 2140 | 2141 | /// SDRAM Timing register 1 2142 | pub SDTR1: RWRegister, 2143 | 2144 | /// SDRAM Timing register 1 2145 | pub SDTR2: RWRegister, 2146 | 2147 | /// SDRAM Command Mode register 2148 | pub SDCMR: RWRegister, 2149 | 2150 | /// SDRAM Refresh Timer register 2151 | pub SDRTR: RWRegister, 2152 | 2153 | /// SDRAM Status register 2154 | pub SDSR: RORegister, 2155 | } 2156 | pub struct ResetValues { 2157 | pub BCR1: u32, 2158 | pub BTR1: u32, 2159 | pub BCR2: u32, 2160 | pub BTR2: u32, 2161 | pub BCR3: u32, 2162 | pub BTR3: u32, 2163 | pub BCR4: u32, 2164 | pub BTR4: u32, 2165 | pub PCR: u32, 2166 | pub SR: u32, 2167 | pub PMEM: u32, 2168 | pub PATT: u32, 2169 | pub ECCR: u32, 2170 | pub BWTR1: u32, 2171 | pub BWTR2: u32, 2172 | pub BWTR3: u32, 2173 | pub BWTR4: u32, 2174 | pub SDCR1: u32, 2175 | pub SDCR2: u32, 2176 | pub SDTR1: u32, 2177 | pub SDTR2: u32, 2178 | pub SDCMR: u32, 2179 | pub SDRTR: u32, 2180 | pub SDSR: u32, 2181 | } 2182 | #[cfg(not(feature = "nosync"))] 2183 | pub struct Instance { 2184 | pub(crate) addr: u32, 2185 | pub(crate) _marker: PhantomData<*const RegisterBlock>, 2186 | } 2187 | #[cfg(not(feature = "nosync"))] 2188 | impl ::core::ops::Deref for Instance { 2189 | type Target = RegisterBlock; 2190 | #[inline(always)] 2191 | fn deref(&self) -> &RegisterBlock { 2192 | unsafe { &*(self.addr as *const _) } 2193 | } 2194 | } 2195 | #[cfg(feature = "rtic")] 2196 | unsafe impl Send for Instance {} 2197 | -------------------------------------------------------------------------------- /src/ral/peripherals/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | pub mod fmc; 3 | -------------------------------------------------------------------------------- /src/ral/register.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | use core::cell::UnsafeCell; 3 | 4 | /// A read-write register of type T. 5 | /// 6 | /// Contains one value of type T and provides volatile read/write functions to it. 7 | /// 8 | /// # Safety 9 | /// This register should be used where reads and writes to this peripheral register do not 10 | /// lead to memory unsafety. For example, it is a poor choice for a DMA target, but less 11 | /// worrisome for a GPIO output data register. 12 | /// 13 | /// Access to this register must be synchronised; if multiple threads (or the main thread and an 14 | /// interrupt service routine) are accessing it simultaneously you may encounter data races. 15 | pub struct RWRegister { 16 | register: UnsafeCell, 17 | } 18 | 19 | impl RWRegister { 20 | /// Reads the value of the register. 21 | #[inline(always)] 22 | pub fn read(&self) -> T { 23 | unsafe { ::core::ptr::read_volatile(self.register.get()) } 24 | } 25 | 26 | /// Writes a new value to the register. 27 | #[inline(always)] 28 | pub fn write(&self, val: T) { 29 | unsafe { ::core::ptr::write_volatile(self.register.get(), val) } 30 | } 31 | } 32 | 33 | /// A read-write register of type T, where read/write access is unsafe. 34 | /// 35 | /// Contains one value of type T and provides volatile read/write functions to it. 36 | /// 37 | /// # Safety 38 | /// This register should be used where reads and writes to this peripheral may invoke 39 | /// undefined behaviour or memory unsafety. For example, any registers you write a memory 40 | /// address into. 41 | /// 42 | /// Access to this register must be synchronised; if multiple threads (or the main thread and an 43 | /// interrupt service routine) are accessing it simultaneously you may encounter data races. 44 | pub struct UnsafeRWRegister { 45 | register: UnsafeCell, 46 | } 47 | 48 | impl UnsafeRWRegister { 49 | /// Reads the value of the register. 50 | #[inline(always)] 51 | pub unsafe fn read(&self) -> T { 52 | ::core::ptr::read_volatile(self.register.get()) 53 | } 54 | 55 | /// Writes a new value to the register. 56 | #[inline(always)] 57 | pub unsafe fn write(&self, val: T) { 58 | ::core::ptr::write_volatile(self.register.get(), val) 59 | } 60 | } 61 | 62 | /// A read-only register of type T. 63 | /// 64 | /// Contains one value of type T and provides a volatile read function to it. 65 | /// 66 | /// # Safety 67 | /// This register should be used where reads and writes to this peripheral register do not 68 | /// lead to memory unsafety. 69 | /// 70 | /// Access to this register must be synchronised; if multiple threads (or the main thread and an 71 | /// interrupt service routine) are accessing it simultaneously you may encounter data races. 72 | pub struct RORegister { 73 | register: UnsafeCell, 74 | } 75 | 76 | impl RORegister { 77 | /// Reads the value of the register. 78 | #[inline(always)] 79 | pub fn read(&self) -> T { 80 | unsafe { ::core::ptr::read_volatile(self.register.get()) } 81 | } 82 | } 83 | 84 | /// A read-only register of type T, where read access is unsafe. 85 | /// 86 | /// Contains one value of type T and provides a volatile read function to it. 87 | /// 88 | /// # Safety 89 | /// This register should be used where reads to this peripheral may invoke 90 | /// undefined behaviour or memory unsafety. 91 | /// 92 | /// Access to this register must be synchronised; if multiple threads (or the main thread and an 93 | /// interrupt service routine) are accessing it simultaneously you may encounter data races. 94 | pub struct UnsafeRORegister { 95 | register: UnsafeCell, 96 | } 97 | 98 | impl UnsafeRORegister { 99 | /// Reads the value of the register. 100 | #[inline(always)] 101 | pub unsafe fn read(&self) -> T { 102 | ::core::ptr::read_volatile(self.register.get()) 103 | } 104 | } 105 | 106 | /// A write-only register of type T. 107 | /// 108 | /// Contains one value of type T and provides a volatile write function to it. 109 | /// 110 | /// # Safety 111 | /// This register should be used where writes to this peripheral register do not lead to memory 112 | /// unsafety. 113 | /// 114 | /// Access to this register must be synchronised; if multiple threads (or the main thread and an 115 | /// interrupt service routine) are accessing it simultaneously you may encounter data races. 116 | pub struct WORegister { 117 | register: UnsafeCell, 118 | } 119 | 120 | impl WORegister { 121 | /// Writes a new value to the register. 122 | #[inline(always)] 123 | pub fn write(&self, val: T) { 124 | unsafe { ::core::ptr::write_volatile(self.register.get(), val) } 125 | } 126 | } 127 | 128 | /// A write-only register of type T, where write access is unsafe. 129 | /// 130 | /// Contains one value of type T and provides a volatile write function to it. 131 | /// 132 | /// # Safety 133 | /// This register should be used where reads and writes to this peripheral may invoke 134 | /// undefined behaviour or memory unsafety. 135 | /// 136 | /// Access to this register must be synchronised; if multiple threads (or the main thread and an 137 | /// interrupt service routine) are accessing it simultaneously you may encounter data races. 138 | pub struct UnsafeWORegister { 139 | register: UnsafeCell, 140 | } 141 | 142 | impl UnsafeWORegister { 143 | /// Writes a new value to the register. 144 | #[inline(always)] 145 | pub unsafe fn write(&self, val: T) { 146 | ::core::ptr::write_volatile(self.register.get(), val) 147 | } 148 | } 149 | 150 | /// Write to a RWRegister or UnsafeRWRegister. 151 | /// 152 | /// # Examples 153 | /// ```rust,ignore 154 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 155 | /// // Safely acquire the peripheral instance (will panic if already acquired) 156 | /// let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 157 | /// 158 | /// // Write some value to the register. 159 | /// write_reg!(stm32ral::gpio, gpioa, ODR, 1<<3); 160 | /// 161 | /// // Write values to specific fields. Unspecified fields are written to 0. 162 | /// write_reg!(stm32ral::gpio, gpioa, MODER, MODER3: Output, MODER4: Analog); 163 | /// 164 | /// // Unsafe access without requiring you to first `take()` the instance 165 | /// unsafe { write_reg!(stm32ral::gpio, GPIOA, MODER, MODER3: Output, MODER4: Analog) }; 166 | /// # } 167 | /// ``` 168 | /// 169 | /// # Usage 170 | /// Like `modify_reg!`, this macro can be used in two ways, either with a single value to write to 171 | /// the whole register, or with multiple fields each with their own value. 172 | /// 173 | /// In both cases, the first arguments are: 174 | /// * the path to the peripheral module: `stm32ral::gpio`, 175 | /// * a reference to the instance of that peripheral: 'gpioa' (anything which dereferences to 176 | /// `RegisterBlock`, such as `Instance`, `&Instance`, `&RegisterBlock`, or 177 | /// `*const RegisterBlock`), 178 | /// * the register you wish you access: `MODER` (a field on the `RegisterBlock`). 179 | /// 180 | /// In the single-value usage, the final argument is just the value to write: 181 | /// ```rust,ignore 182 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 183 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 184 | /// // Turn on PA3 (and turn everything else off). 185 | /// write_reg!(stm32ral::gpio, gpioa, ODR, 1<<3); 186 | /// # } 187 | /// ``` 188 | /// 189 | /// Otherwise, the remaining arguments are each `Field: Value` pairs: 190 | /// ```rust,ignore 191 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 192 | /// // Set PA3 to Output, PA4 to Analog, and everything else to 0 (which is Input). 193 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 194 | /// write_reg!(stm32ral::gpio, gpioa, MODER, MODER3: 0b01, MODER4: 0b11); 195 | /// # } 196 | /// ``` 197 | /// For fields with annotated values, you can also specify a named value: 198 | /// ```rust,ignore 199 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 200 | /// // As above, but with named values. 201 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 202 | /// write_reg!(stm32ral::gpio, gpioa, MODER, MODER3: Output, MODER4: Analog); 203 | /// # } 204 | /// ``` 205 | /// 206 | /// This macro expands to calling `(*$instance).$register.write(value)`, 207 | /// where in the second usage, the value is computed as the bitwise OR of 208 | /// each field value, which are masked and shifted appropriately for the given field. 209 | /// The named values are brought into scope by `use $peripheral::$register::$field::*` for 210 | /// each field. The same constants could just be specified manually: 211 | /// ```rust,ignore 212 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 213 | /// // As above, but being explicit about named values. 214 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 215 | /// write_reg!(stm32ral::gpio, gpioa, MODER, MODER3: stm32ral::gpio::MODER::MODER3::RW::Output, 216 | /// MODER4: stm32ral::gpio::MODER::MODER4::RW::Analog); 217 | /// # } 218 | /// ``` 219 | /// 220 | /// The fully expanded form is equivalent to: 221 | /// ```rust,ignore 222 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 223 | /// // As above, but expanded. 224 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 225 | /// (*gpioa).MODER.write( 226 | /// ((stm32ral::gpio::MODER::MODER3::RW::Output << stm32ral::gpio::MODER::MODER3::offset) 227 | /// & stm32ral::gpio::MODER::MODER3::mask) 228 | /// | 229 | /// ((stm32ral::gpio::MODER::MODER4::RW::Analog << stm32ral::gpio::MODER::MODER4::offset) 230 | /// & stm32ral::gpio::MODER::MODER4::mask) 231 | /// ); 232 | /// # } 233 | /// ``` 234 | /// 235 | /// # Safety 236 | /// This macro will require an unsafe function or block when used with an UnsafeRWRegister, 237 | /// but not if used with RWRegister. 238 | /// 239 | /// When run in an unsafe context, peripheral instances are directly accessible without requiring 240 | /// having called `take()` beforehand: 241 | /// ```rust,ignore 242 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 243 | /// unsafe { write_reg!(stm32ral::gpio, GPIOA, MODER, MODER3: Output, MODER4: Analog) }; 244 | /// # } 245 | /// ``` 246 | /// This works because `GPIOA` is a `*const RegisterBlock` in the `stm32ral::gpio` module; 247 | /// and the macro brings such constants into scope and then dereferences the provided reference. 248 | #[macro_export] 249 | macro_rules! write_reg { 250 | ( $periph:path, $instance:expr, $reg:ident, $( $field:ident : $value:expr ),+ ) => {{ 251 | #[allow(unused_imports)] 252 | use $periph::{*}; 253 | #[allow(unused_imports)] 254 | (*$instance).$reg.write( 255 | $({ use $periph::{$reg::$field::{mask, offset, W::*, RW::*}}; ($value << offset) & mask }) | * 256 | ); 257 | }}; 258 | ( $periph:path, $instance:expr, $reg:ident, $value:expr ) => {{ 259 | #[allow(unused_imports)] 260 | use $periph::{*}; 261 | (*$instance).$reg.write($value); 262 | }}; 263 | } 264 | 265 | /// Modify a RWRegister or UnsafeRWRegister. 266 | /// 267 | /// # Examples 268 | /// ```rust,ignore 269 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 270 | /// // Safely acquire the peripheral instance (will panic if already acquired) 271 | /// let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 272 | /// 273 | /// // Update the register to ensure bit 3 is set. 274 | /// modify_reg!(stm32ral::gpio, gpioa, ODR, |reg| reg | (1<<3)); 275 | /// 276 | /// // Write values to specific fields. Unspecified fields are left unchanged. 277 | /// modify_reg!(stm32ral::gpio, gpioa, MODER, MODER3: Output, MODER4: Analog); 278 | /// 279 | /// // Unsafe access without requiring you to first `take()` the instance 280 | /// unsafe { modify_reg!(stm32ral::gpio, GPIOA, MODER, MODER3: Output, MODER4: Analog) }; 281 | /// # } 282 | /// ``` 283 | /// 284 | /// # Usage 285 | /// Like `write_reg!`, this macro can be used in two ways, either with a modification of the entire 286 | /// register, or by specifying which fields to change and what value to change them to. 287 | /// 288 | /// In both cases, the first arguments are: 289 | /// * the path to the peripheral module: `stm32ral::gpio`, 290 | /// * a reference to the instance of that peripheral: 'gpioa' (anything which dereferences to 291 | /// `RegisterBlock`, such as `Instance`, `&Instance`, `&RegisterBlock`, or 292 | /// `*const RegisterBlock`), 293 | /// * the register you wish you access: `MODER` (a field on the `RegisterBlock`). 294 | /// 295 | /// In the whole-register usage, the final argument is a closure that accepts the current value 296 | /// of the register and returns the new value to write: 297 | /// ```rust,ignore 298 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 299 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 300 | /// // Turn on PA3 without affecting anything else. 301 | /// modify_reg!(stm32ral::gpio, gpioa, ODR, |reg| reg | (1<<3)); 302 | /// # } 303 | /// ``` 304 | /// 305 | /// Otherwise, the remaining arguments are `Field: Value` pairs: 306 | /// ```rust,ignore 307 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 308 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 309 | /// // Set PA3 to Output, PA4 to Analog, and leave everything else unchanged. 310 | /// modify_reg!(stm32ral::gpio, gpioa, MODER, MODER3: 0b01, MODER4: 0b11); 311 | /// # } 312 | /// ``` 313 | /// 314 | /// For fields with annotated values, you can also specify a named value: 315 | /// ```rust,ignore 316 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 317 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 318 | /// // As above, but with named values. 319 | /// modify_reg!(stm32ral::gpio, gpioa, MODER, MODER3: Output, MODER4: Analog); 320 | /// # } 321 | /// ``` 322 | /// 323 | /// This macro expands to calling `(*instance).register.write(value)`. 324 | /// When called with a closure, `(*instance).register.read()` is called, the result 325 | /// passed in to the closure, and the return value of the closure is used for `value`. 326 | /// When called with `Field: Value` arguments, the current value is read and then masked 327 | /// according to the specified fields, and then ORd with the OR of each field value, 328 | /// each masked and shifted appropriately for the field. The named values are brought into scope 329 | /// by `use peripheral::register::field::*` for each field. The same constants could just be 330 | /// specified manually: 331 | /// ```rust,ignore 332 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 333 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 334 | /// // As above, but being explicit about named values. 335 | /// modify_reg!(stm32ral::gpio, gpioa, MODER, MODER3: stm32ral::gpio::MODER::MODER3::RW::Output, 336 | /// MODER4: stm32ral::gpio::MODER::MODER4::RW::Analog); 337 | /// # } 338 | /// ``` 339 | /// 340 | /// The fully expanded form is equivalent to: 341 | /// ```rust,ignore 342 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 343 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 344 | /// // As above, but expanded. 345 | /// (*gpioa).MODER.write( 346 | /// ( 347 | /// // First read the current value... 348 | /// (*gpioa).MODER.read() 349 | /// // Then AND it with an appropriate mask... 350 | /// & 351 | /// !( stm32ral::gpio::MODER::MODER3::mask | stm32ral::gpio::MODER::MODER4::mask ) 352 | /// ) 353 | /// // Then OR with each field value. 354 | /// | 355 | /// ((stm32ral::gpio::MODER::MODER3::RW::Output << stm32ral::gpio::MODER::MODER3::offset) 356 | /// & stm32ral::gpio::MODER::MODER3::mask) 357 | /// | 358 | /// ((stm32ral::gpio::MODER::MODER4::RW::Analog << stm32ral::gpio::MODER::MODER3::offset) 359 | /// & stm32ral::gpio::MODER::MODER3::mask) 360 | /// ); 361 | /// # } 362 | /// ``` 363 | /// 364 | /// # Safety 365 | /// This macro will require an unsafe function or block when used with an UnsafeRWRegister, 366 | /// but not if used with RWRegister. 367 | /// 368 | /// When run in an unsafe context, peripheral instances are directly accessible without requiring 369 | /// having called `take()` beforehand: 370 | /// ```rust,ignore 371 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 372 | /// unsafe { modify_reg!(stm32ral::gpio, GPIOA, MODER, MODER3: Output, MODER4: Analog) }; 373 | /// # } 374 | /// ``` 375 | /// This works because `GPIOA` is a `*const RegisterBlock` in the `stm32ral::gpio` module; 376 | /// and the macro brings such constants into scope and then dereferences the provided reference. 377 | #[macro_export] 378 | macro_rules! modify_reg { 379 | ( $periph:path, $instance:expr, $reg:ident, $( $field:ident : $value:expr ),+ ) => {{ 380 | #[allow(unused_imports)] 381 | use $periph::{*}; 382 | #[allow(unused_imports)] 383 | (*$instance).$reg.write( 384 | ((*$instance).$reg.read() & !( $({ use $periph::{$reg::$field::mask}; mask }) | * )) 385 | | $({ use $periph::{$reg::$field::{mask, offset, W::*, RW::*}}; ($value << offset) & mask }) | *); 386 | }}; 387 | ( $periph:path, $instance:expr, $reg:ident, $fn:expr ) => {{ 388 | #[allow(unused_imports)] 389 | use $periph::{*}; 390 | (*$instance).$reg.write($fn((*$instance).$reg.read())); 391 | }}; 392 | } 393 | 394 | /// Read the value from a RORegister, RWRegister, UnsafeRORegister, or UnsafeRWRegister. 395 | /// 396 | /// # Examples 397 | /// ```rust,ignore 398 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 399 | /// // Safely acquire the peripheral instance (will panic if already acquired) 400 | /// let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 401 | /// 402 | /// // Read the whole register. 403 | /// let val = read_reg!(stm32ral::gpio, gpioa, IDR); 404 | /// 405 | /// // Read one field from the register. 406 | /// let val = read_reg!(stm32ral::gpio, gpioa, IDR, IDR2); 407 | /// 408 | /// // Read multiple fields from the register. 409 | /// let (val1, val2, val3) = read_reg!(stm32ral::gpio, gpioa, IDR, IDR0, IDR1, IDR2); 410 | /// 411 | /// // Check if one field is equal to a specific value, with the field's named values in scope. 412 | /// while read_reg!(stm32ral::gpio, gpioa, IDR, IDR2 == High) {} 413 | /// 414 | /// // Unsafe access without requiring you to first `take()` the instance 415 | /// let val = unsafe { read_reg!(stm32ral::gpio, GPIOA, IDR) }; 416 | /// # } 417 | /// ``` 418 | /// 419 | /// # Usage 420 | /// Like `write_reg!`, this macro can be used multiple ways, either reading the entire register or 421 | /// reading a one or more fields from it and potentially performing a comparison with one field. 422 | /// 423 | /// In all cases, the first arguments are: 424 | /// * the path to the peripheral module: `stm32ral::gpio`, 425 | /// * a reference to the instance of that peripheral: 'gpioa' (anything which dereferences to 426 | /// `RegisterBlock`, such as `Instance`, `&Instance`, `&RegisterBlock`, or 427 | /// `*const RegisterBlock`), 428 | /// * the register you wish to access: `IDR` (a field on the `RegisterBlock`). 429 | /// 430 | /// In the whole-register usage, the macro simply returns the register's value: 431 | /// ```rust,ignore 432 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 433 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 434 | /// // Read the entire value of GPIOA.IDR into `val`. 435 | /// let val = read_reg!(stm32ral::gpio, gpioa, IDR); 436 | /// # } 437 | /// ``` 438 | /// 439 | /// For reading individual fields, the macro masks and shifts appropriately: 440 | /// ```rust,ignore 441 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 442 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 443 | /// // Read just the value of the field GPIOA.IDR2 into `val`. 444 | /// let val = read_reg!(stm32ral::gpio, gpioa, IDR, IDR2); 445 | /// 446 | /// // As above, but expanded for exposition: 447 | /// let val = ((*gpioa).IDR.read() & stm32ral::gpio::IDR::IDR2::mask) 448 | /// >> stm32ral::gpio::IDR::IDR2::offset; 449 | /// 450 | /// // Read multiple fields 451 | /// let (val1, val2) = read_reg!(stm32ral::gpio, gpioa, IDR, IDR2, IDR3); 452 | /// 453 | /// // As above, but expanded for exposition: 454 | /// let (val1, val2) = { let val = (*gpioa).IDR.read(); 455 | /// ((val & stm32ral::gpio::IDR::IDR2::mask) >> stm32ral::gpio::IDR::IDR2::offset, 456 | /// (val & stm32ral::gpio::IDR::IDR3::mask) >> stm32ral::gpio::IDR::IDR3::offset, 457 | /// )}; 458 | /// # } 459 | /// ``` 460 | /// 461 | /// For comparing a single field, the macro masks and shifts and then performs the comparison: 462 | /// ```rust,ignore 463 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 464 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 465 | /// # let rcc = stm32ral::rcc::RCC::take().unwrap(); 466 | /// // Loop while PA2 is High. 467 | /// while read_reg!(stm32ral::gpio, gpioa, IDR, IDR2 == High) {} 468 | /// 469 | /// // Only proceed if the clock is not the HSI. 470 | /// if read_reg!(stm32ral::rcc, rcc, CFGR, SWS != HSI) { } 471 | /// 472 | /// // Equivalent expansion: 473 | /// if (((*rcc).CFGR.read() & stm32ral::rcc::CFGR::SWS::mask) 474 | /// >> stm32ral::rcc::CFGR::SWS::offset) != stm32ral::rcc::CFGR::SWS::R::HSI { } 475 | /// # } 476 | /// ``` 477 | /// 478 | /// # Safety 479 | /// This macro will require an unsafe function or block when used with an UnsafeRWRegister or 480 | /// UnsafeRORegister, but not if used with RWRegister, or RORegister. 481 | /// 482 | /// When run in an unsafe context, peripheral instances are directly accessible without requiring 483 | /// having called `take()` beforehand: 484 | /// ```rust,ignore 485 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 486 | /// let val = unsafe { read_reg!(stm32ral::gpio, GPIOA, MODER) }; 487 | /// # } 488 | /// ``` 489 | /// This works because `GPIOA` is a `*const RegisterBlock` in the `stm32ral::gpio` module; 490 | /// and the macro brings such constants into scope and then dereferences the provided reference. 491 | #[macro_export] 492 | macro_rules! read_reg { 493 | ( $periph:path, $instance:expr, $reg:ident, $( $field:ident ),+ ) => {{ 494 | #[allow(unused_imports)] 495 | use $periph::{*}; 496 | let val = ((*$instance).$reg.read()); 497 | ( $({ 498 | #[allow(unused_imports)] 499 | use $periph::{$reg::$field::{mask, offset, R::*, RW::*}}; 500 | (val & mask) >> offset 501 | }) , *) 502 | }}; 503 | ( $periph:path, $instance:expr, $reg:ident, $field:ident $($cmp:tt)* ) => {{ 504 | #[allow(unused_imports)] 505 | use $periph::{*}; 506 | #[allow(unused_imports)] 507 | use $periph::{$reg::$field::{mask, offset, R::*, RW::*}}; 508 | (((*$instance).$reg.read() & mask) >> offset) $($cmp)* 509 | }}; 510 | ( $periph:path, $instance:expr, $reg:ident ) => {{ 511 | #[allow(unused_imports)] 512 | use $periph::{*}; 513 | ((*$instance).$reg.read()) 514 | }}; 515 | } 516 | 517 | /// Reset a RWRegister, UnsafeRWRegister, WORegister, or UnsafeWORegister to its reset value. 518 | /// 519 | /// # Examples 520 | /// ```rust,ignore 521 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 522 | /// // Safely acquire the peripheral instance (will panic if already acquired) 523 | /// let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 524 | /// 525 | /// // Reset PA14 and PA15 to their reset state 526 | /// reset_reg!(stm32ral::gpio, gpioa, GPIOA, MODER, MODER14, MODER15); 527 | /// 528 | /// // Reset the entire GPIOA.MODER to its reset state 529 | /// reset_reg!(stm32ral::gpio, gpioa, GPIOA, MODER); 530 | /// # } 531 | /// ``` 532 | /// 533 | /// # Usage 534 | /// Like `write_reg!`, this macro can be used in two ways, either resetting the entire register 535 | /// or just resetting specific fields within in. The register or fields are written with their 536 | /// reset values. 537 | /// 538 | /// In both cases, the first arguments are: 539 | /// * the path to the peripheral module: `stm32ral::gpio`, 540 | /// * a reference to the instance of that peripheral: 'gpioa' (anything which dereferences to 541 | /// `RegisterBlock`, such as `Instance`, `&Instance`, `&RegisterBlock`, or 542 | /// `*const RegisterBlock`), 543 | /// * the module for the instance of that peripheral: `GPIOA`, 544 | /// * the register you wish to access: `MODER` (a field on the `RegisterBlock`). 545 | /// 546 | /// In the whole-register usage, that's it: 547 | /// ```rust,ignore 548 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 549 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 550 | /// // Reset the entire GPIOA.MODER 551 | /// reset_reg!(stm32ral::gpio, gpioa, GPIOA, MODER); 552 | /// # } 553 | /// ``` 554 | /// 555 | /// Otherwise, the remaining arguments are each field names: 556 | /// ```rust,ignore 557 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 558 | /// # let gpioa = stm32ral::gpio::GPIOA::take().unwrap(); 559 | /// // Reset the JTAG pins 560 | /// reset_reg!(stm32ral::gpio, gpioa, GPIOA, MODER, MODER13, MODER14, MODER15); 561 | /// reset_reg!(stm32ral::gpio, gpioa, GPIOB, MODER, MODER3, MODER4); 562 | /// # } 563 | /// ``` 564 | /// 565 | /// The second form is only available to RWRegister and UnsafeRWRegister, since `.read()` is 566 | /// not available for WORegister and UnsafeWORegister. 567 | /// 568 | /// This macro expands to calling `(*$instance).$register.write(value)`, where 569 | /// `value` is either the register's reset value, or the current read value of the register 570 | /// masked appropriately and combined with the reset value for each field. 571 | /// 572 | /// # Safety 573 | /// This macro will require an unsafe function or block when used with an UnsafeRWRegister or 574 | /// UnsafeRORegister, but not if used with RWRegister or RORegister. 575 | /// 576 | /// When run in an unsafe context, peripheral instances are directly accessible without requiring 577 | /// having called `take()` beforehand: 578 | /// ```rust,ignore 579 | /// # use stm32ral::{read_reg, write_reg, modify_reg, reset_reg}; fn main() { 580 | /// unsafe { reset_reg!(stm32ral::gpio, GPIOA, GPIOA, MODER) }; 581 | /// # } 582 | /// ``` 583 | /// This works because `GPIOA` is a `*const RegisterBlock` in the `stm32ral::gpio` module; 584 | /// and the macro brings such constants into scope and then dereferences the provided reference. 585 | /// 586 | /// Note that the second argument is a `*const` and the third is a path; despite both being written 587 | /// `GPIOA` they are not the same thing. 588 | #[macro_export] 589 | macro_rules! reset_reg { 590 | ( $periph:path, $instance:expr, $instancemod:path, $reg:ident, $( $field:ident ),+ ) => {{ 591 | #[allow(unused_imports)] 592 | use $periph::{*}; 593 | use $periph::{$instancemod::{reset}}; 594 | #[allow(unused_imports)] 595 | (*$instance).$reg.write({ 596 | let resetmask: u32 = $({ use $periph::{$reg::$field::mask}; mask }) | *; 597 | ((*$instance).$reg.read() & !resetmask) | (reset.$reg & resetmask) 598 | }); 599 | }}; 600 | ( $periph:path, $instance:expr, $instancemod:path, $reg:ident ) => {{ 601 | #[allow(unused_imports)] 602 | use $periph::{*}; 603 | use $periph::{$instancemod::{reset}}; 604 | (*$instance).$reg.write(reset.$reg); 605 | }}; 606 | } 607 | -------------------------------------------------------------------------------- /src/sdram.rs: -------------------------------------------------------------------------------- 1 | //! HAL for external SDRAM 2 | 3 | use core::cmp; 4 | use core::convert::TryInto; 5 | use core::marker::PhantomData; 6 | 7 | use embedded_hal::delay::DelayNs; 8 | 9 | use crate::fmc::{AddressPinSet, FmcBank, FmcRegisters}; 10 | use crate::FmcPeripheral; 11 | 12 | use crate::ral::{fmc, modify_reg, write_reg}; 13 | 14 | /// FMC SDRAM Configuration Structure definition 15 | /// 16 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 17 | #[derive(Clone, Copy, Debug, PartialEq)] 18 | pub struct SdramConfiguration { 19 | /// Number of bits of column address 20 | pub column_bits: u8, 21 | /// Number of bits of column address 22 | pub row_bits: u8, 23 | /// Memory device width 24 | pub memory_data_width: u8, 25 | /// Number of the device's internal banks 26 | pub internal_banks: u8, 27 | /// SDRAM CAS latency in number of memory clock cycles 28 | pub cas_latency: u8, 29 | /// Enables the SDRAM device to be accessed in write mode 30 | pub write_protection: bool, 31 | /// This bit enable the SDRAM controller to anticipate the next read 32 | pub read_burst: bool, 33 | /// Delay in system clock cycles on read data path 34 | pub read_pipe_delay_cycles: u8, 35 | } 36 | 37 | /// FMC SDRAM Timing parameters structure definition 38 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 39 | #[derive(Clone, Copy, Debug, PartialEq)] 40 | pub struct SdramTiming { 41 | /// Time between applying a valid clock and any command other than 42 | /// COMMAND INHIBIT or NOP 43 | pub startup_delay_ns: u32, 44 | /// Maximum SD clock frequency to make timing 45 | pub max_sd_clock_hz: u32, 46 | /// Period between refresh cycles in nanoseconds 47 | pub refresh_period_ns: u32, 48 | /// Delay between a LOAD MODE register command and an ACTIVATE command 49 | pub mode_register_to_active: u32, 50 | /// Delay from releasing self refresh to next command 51 | pub exit_self_refresh: u32, 52 | /// Delay between an ACTIVATE and a PRECHARGE command 53 | pub active_to_precharge: u32, 54 | /// Auto refresh command duration 55 | pub row_cycle: u32, 56 | /// Delay between a PRECHARGE command and another command 57 | pub row_precharge: u32, 58 | /// Delay between an ACTIVATE command and READ/WRITE command 59 | pub row_to_column: u32, 60 | } 61 | 62 | /// Respresents a model of SDRAM chip 63 | pub trait SdramChip { 64 | /// Value of the mode register 65 | const MODE_REGISTER: u16; 66 | 67 | /// SDRAM controller configuration 68 | const CONFIG: SdramConfiguration; 69 | 70 | /// Timing parameters 71 | const TIMING: SdramTiming; 72 | } 73 | 74 | /// SDRAM Controller 75 | #[allow(missing_debug_implementations)] 76 | pub struct Sdram { 77 | /// SDRAM bank 78 | target_bank: SdramTargetBank, 79 | /// FMC memory bank to use 80 | fmc_bank: FmcBank, 81 | /// Parameters for the SDRAM IC 82 | _chip: PhantomData, 83 | /// FMC peripheral 84 | fmc: FMC, 85 | /// Register access 86 | regs: FmcRegisters, 87 | } 88 | 89 | /// SDRAM Commands 90 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 91 | #[derive(Clone, Copy, Debug, PartialEq)] 92 | #[allow(unused)] 93 | enum SdramCommand { 94 | NormalMode, 95 | ClkEnable, 96 | Pall, 97 | Autorefresh(u8), 98 | LoadMode(u16), 99 | Selfrefresh, 100 | Powerdown, 101 | } 102 | /// Target bank for SDRAM commands 103 | #[derive(Clone, Copy, Debug, PartialEq)] 104 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 105 | #[allow(unused)] 106 | pub enum SdramTargetBank { 107 | /// Targeting the 1st SDRAM bank 108 | Bank1, 109 | /// Targeting the 2nd SDRAM bank 110 | Bank2, 111 | /// Targeting both SDRAM banks 112 | Both, 113 | } 114 | impl From for SdramTargetBank { 115 | fn from(n: u32) -> Self { 116 | match n { 117 | 1 => SdramTargetBank::Bank1, 118 | 2 => SdramTargetBank::Bank2, 119 | _ => unimplemented!(), 120 | } 121 | } 122 | } 123 | 124 | /// SDRAM target bank and corresponding FMC Bank 125 | pub trait SdramPinSet { 126 | /// External SDRAM bank 127 | const TARGET: SdramTargetBank; 128 | /// Corresponding FMC bank to map this to 129 | const FMC: FmcBank; 130 | } 131 | 132 | /// Type to mark SDRAM on Bank 1 of FMC controller 133 | #[derive(Clone, Copy, Debug)] 134 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 135 | pub struct SdramBank1; 136 | impl SdramPinSet for SdramBank1 { 137 | const TARGET: SdramTargetBank = SdramTargetBank::Bank1; 138 | const FMC: FmcBank = FmcBank::Bank5; 139 | } 140 | 141 | /// Type to mark SDRAM on Bank 2 of FMC controller 142 | #[derive(Clone, Copy, Debug)] 143 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 144 | pub struct SdramBank2; 145 | impl SdramPinSet for SdramBank2 { 146 | const TARGET: SdramTargetBank = SdramTargetBank::Bank2; 147 | const FMC: FmcBank = FmcBank::Bank6; 148 | } 149 | 150 | /// Set of pins for an SDRAM, that corresponds to a specific bank 151 | pub trait PinsSdram { 152 | /// The number of SDRAM banks addressable with this set of pins 153 | const NUMBER_INTERNAL_BANKS: u8; 154 | } 155 | 156 | /// Like `modfiy_reg`, but applies to bank 1 or 2 based on a varaiable 157 | macro_rules! modify_reg_banked { 158 | ( $periph:path, $instance:expr, $bank:expr, $reg1:ident, $reg2:ident, $( $field:ident : $value:expr ),+ ) => {{ 159 | use SdramTargetBank::*; 160 | 161 | match $bank { 162 | Bank1 => modify_reg!( $periph, $instance, $reg1, $( $field : $value ),*), 163 | Bank2 => modify_reg!( $periph, $instance, $reg2, $( $field : $value ),*), 164 | _ => panic!(), 165 | } 166 | }}; 167 | } 168 | 169 | impl Sdram { 170 | /// New SDRAM instance 171 | /// 172 | /// `_pins` must be a set of pins connecting to an SDRAM on the FMC 173 | /// controller 174 | /// 175 | /// # Panics 176 | /// 177 | /// * Panics if there are not enough address lines in `PINS` to access the 178 | /// whole SDRAM 179 | /// 180 | /// * Panics if there are not enough bank address lines in `PINS` to access 181 | /// the whole SDRAM 182 | pub fn new(fmc: FMC, _pins: PINS, _chip: IC) -> Self 183 | where 184 | PINS: PinsSdram, 185 | ADDR: AddressPinSet, 186 | BANK: SdramPinSet, 187 | { 188 | assert!( 189 | ADDR::ADDRESS_PINS >= IC::CONFIG.row_bits, 190 | "Not enough address pins to access all SDRAM rows" 191 | ); 192 | assert!( 193 | ADDR::ADDRESS_PINS >= IC::CONFIG.column_bits, 194 | "Not enough address pins to access all SDRAM colums" 195 | ); 196 | assert!( 197 | PINS::NUMBER_INTERNAL_BANKS >= IC::CONFIG.internal_banks, 198 | "Not enough bank address pins to access all internal banks" 199 | ); 200 | 201 | fmc_trace!("Bank selected via pins: {}.", BANK::TARGET); 202 | 203 | Sdram { 204 | target_bank: BANK::TARGET, 205 | fmc_bank: BANK::FMC, 206 | _chip: PhantomData, 207 | fmc, 208 | regs: FmcRegisters::new::(), 209 | } 210 | } 211 | 212 | /// New SDRAM instance 213 | /// 214 | /// `bank` denotes which SDRAM bank to target. This can be either bank 1 or 215 | /// bank 2. 216 | /// 217 | /// # Safety 218 | /// 219 | /// The pins are not checked against the requirements for the SDRAM chip. So 220 | /// you may be able to initialise a SDRAM without enough pins to access the 221 | /// whole memory 222 | pub fn new_unchecked( 223 | fmc: FMC, 224 | bank: impl Into, 225 | _chip: IC, 226 | ) -> Self { 227 | // Select default bank mapping 228 | let target_bank = bank.into(); 229 | let fmc_bank = match target_bank { 230 | SdramTargetBank::Bank1 => FmcBank::Bank5, 231 | SdramTargetBank::Bank2 => FmcBank::Bank6, 232 | _ => unimplemented!(), 233 | }; 234 | 235 | Sdram { 236 | target_bank, 237 | fmc_bank, 238 | _chip: PhantomData, 239 | fmc, 240 | regs: FmcRegisters::new::(), 241 | } 242 | } 243 | 244 | /// Initialise SDRAM instance. Delay is used to wait the SDRAM powerup 245 | /// delay 246 | /// 247 | /// Returns a raw pointer to the memory-mapped SDRAM block 248 | /// 249 | /// # Panics 250 | /// 251 | /// * Panics if any setting in `IC::CONFIG` cannot be achieved 252 | /// 253 | /// * Panics if the FMC source clock is too fast for 254 | /// maximum SD clock in `IC::TIMING` 255 | pub fn init(&mut self, delay: &mut D) -> *mut u32 256 | where 257 | D: DelayNs, 258 | { 259 | use SdramCommand::*; 260 | 261 | // Select bank 262 | let bank = self.target_bank; 263 | 264 | // Calcuate SD clock 265 | let (sd_clock_hz, divide) = { 266 | let fmc_source_ck_hz = self.fmc.source_clock_hz(); 267 | let sd_clock_wanted = IC::TIMING.max_sd_clock_hz; 268 | 269 | // Divider, round up. At least 2 270 | let divide: u32 = cmp::max( 271 | (fmc_source_ck_hz + sd_clock_wanted - 1) / sd_clock_wanted, 272 | 2, 273 | ); 274 | 275 | // Max 3 276 | assert!(divide <= 3, 277 | "Source clock too fast for required SD_CLOCK. The maximum division ratio is 3"); 278 | 279 | let sd_clock_hz = fmc_source_ck_hz / divide; 280 | (sd_clock_hz, divide) 281 | }; 282 | 283 | fmc_trace!( 284 | "FMC clock {:?} (/{}, Max {:?})", 285 | sd_clock_hz, 286 | divide, 287 | IC::TIMING.max_sd_clock_hz 288 | ); 289 | 290 | unsafe { 291 | // Enable memory controller AHB register access 292 | self.fmc.enable(); 293 | 294 | // Program device features and timing 295 | self.set_features_timings(IC::CONFIG, IC::TIMING, divide); 296 | 297 | // Enable memory controller 298 | self.fmc.memory_controller_enable(); 299 | 300 | // Step 1: Send a clock configuration enable command 301 | self.send_command(ClkEnable, bank); 302 | 303 | // Step 2: SDRAM powerup delay 304 | let startup_delay_us = (IC::TIMING.startup_delay_ns + 999) / 1000; 305 | fmc_trace!("Startup delay: {} us", startup_delay_us); 306 | 307 | delay.delay_us(startup_delay_us.try_into().unwrap()); 308 | 309 | // Step 3: Send a PALL (precharge all) command 310 | self.send_command(Pall, bank); 311 | 312 | // Step 4: Send eight auto refresh commands 313 | self.send_command(Autorefresh(8), bank); 314 | 315 | // Step 5: Program the SDRAM's mode register 316 | self.send_command(LoadMode(IC::MODE_REGISTER), bank); 317 | 318 | // Step 6: Set the refresh rate counter 319 | // period (ns) * frequency (hz) / 10^9 = count 320 | let refresh_counter_top = ((IC::TIMING.refresh_period_ns as u64 321 | * sd_clock_hz as u64) 322 | / 1_000_000_000) 323 | - 20; 324 | assert!( 325 | refresh_counter_top >= 41 && refresh_counter_top < (1 << 13), 326 | "Impossible configuration for H7 FMC Controller" 327 | ); 328 | 329 | fmc_trace!("SDRTR: count {}", refresh_counter_top); 330 | 331 | modify_reg!( 332 | fmc, 333 | self.regs.global(), 334 | SDRTR, 335 | COUNT: refresh_counter_top as u32 336 | ); 337 | } 338 | 339 | #[cfg(feature = "trace-register-values")] 340 | { 341 | use crate::read_reg; 342 | fmc_trace!( 343 | "BCR1: 0x{:x}", 344 | read_reg!(fmc, self.regs.global(), BCR1) 345 | ); 346 | fmc_trace!( 347 | "BTR1: 0x{:x}", 348 | read_reg!(fmc, self.regs.global(), BTR1) 349 | ); 350 | fmc_trace!( 351 | "BCR2: 0x{:x}", 352 | read_reg!(fmc, self.regs.global(), BCR2) 353 | ); 354 | fmc_trace!( 355 | "BTR2: 0x{:x}", 356 | read_reg!(fmc, self.regs.global(), BTR2) 357 | ); 358 | fmc_trace!( 359 | "BCR3: 0x{:x}", 360 | read_reg!(fmc, self.regs.global(), BCR3) 361 | ); 362 | fmc_trace!( 363 | "BTR3: 0x{:x}", 364 | read_reg!(fmc, self.regs.global(), BTR3) 365 | ); 366 | fmc_trace!( 367 | "BCR4: 0x{:x}", 368 | read_reg!(fmc, self.regs.global(), BCR4) 369 | ); 370 | fmc_trace!( 371 | "BTR4: 0x{:x}", 372 | read_reg!(fmc, self.regs.global(), BTR4) 373 | ); 374 | fmc_trace!( 375 | "SDCR1: 0x{:x}", 376 | read_reg!(fmc, self.regs.global(), SDCR1) 377 | ); 378 | fmc_trace!( 379 | "SDCR2: 0x{:x}", 380 | read_reg!(fmc, self.regs.global(), SDCR2) 381 | ); 382 | fmc_trace!( 383 | "SDTR1: 0x{:x}", 384 | read_reg!(fmc, self.regs.global(), SDTR1) 385 | ); 386 | fmc_trace!( 387 | "SDTR2: 0x{:x}", 388 | read_reg!(fmc, self.regs.global(), SDTR2) 389 | ); 390 | fmc_trace!( 391 | "SDCMR: 0x{:x}", 392 | read_reg!(fmc, self.regs.global(), SDCMR) 393 | ); 394 | fmc_trace!( 395 | "SDRTR: 0x{:x}", 396 | read_reg!(fmc, self.regs.global(), SDRTR) 397 | ); 398 | } 399 | 400 | // Memory now initialised. Return base address 401 | self.fmc_bank.ptr() 402 | } 403 | 404 | /// Program memory device features and timings 405 | /// 406 | /// # Safety 407 | /// 408 | /// Some settings are common between both banks. Calling this function 409 | /// mutliple times with different banks and different configurations is 410 | /// unsafe. 411 | /// 412 | /// For example, see RM0433 rev 7 Section 22.9.3 413 | unsafe fn set_features_timings( 414 | &mut self, 415 | config: SdramConfiguration, 416 | timing: SdramTiming, 417 | sd_clock_divide: u32, 418 | ) { 419 | // Features ---- SDCR REGISTER 420 | 421 | // CAS latency 1 ~ 3 cycles 422 | assert!( 423 | config.cas_latency >= 1 && config.cas_latency <= 3, 424 | "Impossible configuration for FMC Controller" 425 | ); 426 | 427 | // Row Bits: 11 ~ 13 428 | assert!( 429 | config.row_bits >= 11 && config.row_bits <= 13, 430 | "Impossible configuration for FMC Controller" 431 | ); 432 | 433 | // Column bits: 8 ~ 11 434 | assert!( 435 | config.column_bits >= 8 && config.column_bits <= 11, 436 | "Impossible configuration for FMC Controller" 437 | ); 438 | 439 | // Read Pipe Delay Cycles 0 ~ 2 440 | assert!( 441 | config.read_pipe_delay_cycles <= 2, 442 | "Impossible configuration for FMC Controller" 443 | ); 444 | 445 | // Common settings written to SDCR1 only 446 | modify_reg!(fmc, self.regs.global(), SDCR1, 447 | RPIPE: config.read_pipe_delay_cycles as u32, 448 | RBURST: config.read_burst as u32, 449 | SDCLK: sd_clock_divide); 450 | 451 | modify_reg_banked!(fmc, self.regs.global(), 452 | self.target_bank, SDCR1, SDCR2, 453 | // fields 454 | WP: config.write_protection as u32, 455 | CAS: config.cas_latency as u32, 456 | NB: 457 | match config.internal_banks { 458 | 2 => 0, 459 | 4 => 1, 460 | _ => { 461 | panic!("Impossible configuration for FMC Controller") 462 | } 463 | }, 464 | MWID: 465 | match config.memory_data_width { 466 | 8 => 0, 467 | 16 => 1, 468 | 32 => 2, 469 | _ => { 470 | panic!("Impossible configuration for FMC Controller") 471 | } 472 | }, 473 | NR: config.row_bits as u32 - 11, 474 | NC: config.column_bits as u32 - 8); 475 | 476 | // Timing ---- SDTR REGISTER 477 | 478 | // Self refresh >= ACTIVE to PRECHARGE 479 | let minimum_self_refresh = timing.active_to_precharge; 480 | 481 | // Write recovery - Self refresh 482 | let write_recovery_self_refresh = 483 | minimum_self_refresh - timing.row_to_column; 484 | // Write recovery - WRITE command to PRECHARGE command 485 | let write_recovery_row_cycle = 486 | timing.row_cycle - timing.row_to_column - timing.row_precharge; 487 | let write_recovery = 488 | cmp::max(write_recovery_self_refresh, write_recovery_row_cycle); 489 | 490 | // Common seting written to SDTR1 only 491 | modify_reg!(fmc, self.regs.global(), SDTR1, 492 | TRC: timing.row_cycle - 1, 493 | TRP: timing.row_precharge - 1 494 | ); 495 | 496 | modify_reg_banked!(fmc, self.regs.global(), 497 | self.target_bank, SDTR1, SDTR2, 498 | // fields 499 | TRCD: timing.row_to_column - 1, 500 | TWR: write_recovery - 1, 501 | TRAS: minimum_self_refresh - 1, 502 | TXSR: timing.exit_self_refresh - 1, 503 | TMRD: timing.mode_register_to_active - 1 504 | ); 505 | } 506 | 507 | /// Send command to SDRAM 508 | unsafe fn send_command( 509 | &mut self, 510 | mode: SdramCommand, 511 | target: SdramTargetBank, 512 | ) { 513 | use SdramCommand::*; 514 | use SdramTargetBank::*; 515 | 516 | // Command 517 | let (cmd, number_refresh, mode_reg) = match mode { 518 | NormalMode => (0x00, 1, 0), 519 | ClkEnable => (0x01, 1, 0), 520 | Pall => (0x02, 1, 0), 521 | Autorefresh(a) => (0x03, a, 0), // Autorefresh 522 | LoadMode(mr) => (0x04, 1, mr), // Mode register 523 | Selfrefresh => (0x05, 1, 0), 524 | Powerdown => (0x06, 1, 0), 525 | }; 526 | // Bank for issuing command 527 | let (b1, b2) = match target { 528 | Bank1 => (1, 0), 529 | Bank2 => (0, 1), 530 | Both => (1, 1), 531 | }; 532 | 533 | // Write to SDCMR 534 | write_reg!( 535 | fmc, 536 | self.regs.global(), 537 | SDCMR, 538 | MRD: mode_reg as u32, 539 | NRFS: number_refresh as u32, 540 | CTB1: b1, 541 | CTB2: b2, 542 | MODE: cmd 543 | ); 544 | 545 | #[cfg(feature = "trace-register-values")] 546 | fmc_trace!( 547 | "Modifying SDCMR: mrd {}, nrfs {}, ctb1 {}, ctb2 {}, mode {}", 548 | mode_reg, 549 | number_refresh, 550 | b1, 551 | b2, 552 | cmd 553 | ); 554 | } 555 | } 556 | -------------------------------------------------------------------------------- /tests/dummy_pins.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | 3 | use stm32_fmc::*; 4 | 5 | pub struct PinThatsA0; 6 | impl A0 for PinThatsA0 {} 7 | pub struct PinThatsA1; 8 | impl A1 for PinThatsA1 {} 9 | pub struct PinThatsA10; 10 | impl A10 for PinThatsA10 {} 11 | pub struct PinThatsA11; 12 | impl A11 for PinThatsA11 {} 13 | pub struct PinThatsA12; 14 | impl A12 for PinThatsA12 {} 15 | pub struct PinThatsA13; 16 | impl A13 for PinThatsA13 {} 17 | pub struct PinThatsA14; 18 | impl A14 for PinThatsA14 {} 19 | pub struct PinThatsA15; 20 | impl A15 for PinThatsA15 {} 21 | pub struct PinThatsA16; 22 | impl A16 for PinThatsA16 {} 23 | pub struct PinThatsA17; 24 | impl A17 for PinThatsA17 {} 25 | pub struct PinThatsA18; 26 | impl A18 for PinThatsA18 {} 27 | pub struct PinThatsA19; 28 | impl A19 for PinThatsA19 {} 29 | pub struct PinThatsA2; 30 | impl A2 for PinThatsA2 {} 31 | pub struct PinThatsA20; 32 | impl A20 for PinThatsA20 {} 33 | pub struct PinThatsA21; 34 | impl A21 for PinThatsA21 {} 35 | pub struct PinThatsA22; 36 | impl A22 for PinThatsA22 {} 37 | pub struct PinThatsA23; 38 | impl A23 for PinThatsA23 {} 39 | pub struct PinThatsA24; 40 | impl A24 for PinThatsA24 {} 41 | pub struct PinThatsA25; 42 | impl A25 for PinThatsA25 {} 43 | pub struct PinThatsA3; 44 | impl A3 for PinThatsA3 {} 45 | pub struct PinThatsA4; 46 | impl A4 for PinThatsA4 {} 47 | pub struct PinThatsA5; 48 | impl A5 for PinThatsA5 {} 49 | pub struct PinThatsA6; 50 | impl A6 for PinThatsA6 {} 51 | pub struct PinThatsA7; 52 | impl A7 for PinThatsA7 {} 53 | pub struct PinThatsA8; 54 | impl A8 for PinThatsA8 {} 55 | pub struct PinThatsA9; 56 | impl A9 for PinThatsA9 {} 57 | pub struct PinThatsBA0; 58 | impl BA0 for PinThatsBA0 {} 59 | pub struct PinThatsBA1; 60 | impl BA1 for PinThatsBA1 {} 61 | pub struct PinThatsCLK; 62 | impl CLK for PinThatsCLK {} 63 | pub struct PinThatsD0; 64 | impl D0 for PinThatsD0 {} 65 | pub struct PinThatsD1; 66 | impl D1 for PinThatsD1 {} 67 | pub struct PinThatsD10; 68 | impl D10 for PinThatsD10 {} 69 | pub struct PinThatsD11; 70 | impl D11 for PinThatsD11 {} 71 | pub struct PinThatsD12; 72 | impl D12 for PinThatsD12 {} 73 | pub struct PinThatsD13; 74 | impl D13 for PinThatsD13 {} 75 | pub struct PinThatsD14; 76 | impl D14 for PinThatsD14 {} 77 | pub struct PinThatsD15; 78 | impl D15 for PinThatsD15 {} 79 | pub struct PinThatsD16; 80 | impl D16 for PinThatsD16 {} 81 | pub struct PinThatsD17; 82 | impl D17 for PinThatsD17 {} 83 | pub struct PinThatsD18; 84 | impl D18 for PinThatsD18 {} 85 | pub struct PinThatsD19; 86 | impl D19 for PinThatsD19 {} 87 | pub struct PinThatsD2; 88 | impl D2 for PinThatsD2 {} 89 | pub struct PinThatsD20; 90 | impl D20 for PinThatsD20 {} 91 | pub struct PinThatsD21; 92 | impl D21 for PinThatsD21 {} 93 | pub struct PinThatsD22; 94 | impl D22 for PinThatsD22 {} 95 | pub struct PinThatsD23; 96 | impl D23 for PinThatsD23 {} 97 | pub struct PinThatsD24; 98 | impl D24 for PinThatsD24 {} 99 | pub struct PinThatsD25; 100 | impl D25 for PinThatsD25 {} 101 | pub struct PinThatsD26; 102 | impl D26 for PinThatsD26 {} 103 | pub struct PinThatsD27; 104 | impl D27 for PinThatsD27 {} 105 | pub struct PinThatsD28; 106 | impl D28 for PinThatsD28 {} 107 | pub struct PinThatsD29; 108 | impl D29 for PinThatsD29 {} 109 | pub struct PinThatsD3; 110 | impl D3 for PinThatsD3 {} 111 | pub struct PinThatsD30; 112 | impl D30 for PinThatsD30 {} 113 | pub struct PinThatsD31; 114 | impl D31 for PinThatsD31 {} 115 | pub struct PinThatsD4; 116 | impl D4 for PinThatsD4 {} 117 | pub struct PinThatsD5; 118 | impl D5 for PinThatsD5 {} 119 | pub struct PinThatsD6; 120 | impl D6 for PinThatsD6 {} 121 | pub struct PinThatsD7; 122 | impl D7 for PinThatsD7 {} 123 | pub struct PinThatsD8; 124 | impl D8 for PinThatsD8 {} 125 | pub struct PinThatsD9; 126 | impl D9 for PinThatsD9 {} 127 | pub struct PinThatsDA0; 128 | impl DA0 for PinThatsDA0 {} 129 | pub struct PinThatsDA1; 130 | impl DA1 for PinThatsDA1 {} 131 | pub struct PinThatsDA10; 132 | impl DA10 for PinThatsDA10 {} 133 | pub struct PinThatsDA11; 134 | impl DA11 for PinThatsDA11 {} 135 | pub struct PinThatsDA12; 136 | impl DA12 for PinThatsDA12 {} 137 | pub struct PinThatsDA13; 138 | impl DA13 for PinThatsDA13 {} 139 | pub struct PinThatsDA14; 140 | impl DA14 for PinThatsDA14 {} 141 | pub struct PinThatsDA15; 142 | impl DA15 for PinThatsDA15 {} 143 | pub struct PinThatsDA2; 144 | impl DA2 for PinThatsDA2 {} 145 | pub struct PinThatsDA3; 146 | impl DA3 for PinThatsDA3 {} 147 | pub struct PinThatsDA4; 148 | impl DA4 for PinThatsDA4 {} 149 | pub struct PinThatsDA5; 150 | impl DA5 for PinThatsDA5 {} 151 | pub struct PinThatsDA6; 152 | impl DA6 for PinThatsDA6 {} 153 | pub struct PinThatsDA7; 154 | impl DA7 for PinThatsDA7 {} 155 | pub struct PinThatsDA8; 156 | impl DA8 for PinThatsDA8 {} 157 | pub struct PinThatsDA9; 158 | impl DA9 for PinThatsDA9 {} 159 | pub struct PinThatsINT; 160 | impl INT for PinThatsINT {} 161 | pub struct PinThatsNBL0; 162 | impl NBL0 for PinThatsNBL0 {} 163 | pub struct PinThatsNBL1; 164 | impl NBL1 for PinThatsNBL1 {} 165 | pub struct PinThatsNBL2; 166 | impl NBL2 for PinThatsNBL2 {} 167 | pub struct PinThatsNBL3; 168 | impl NBL3 for PinThatsNBL3 {} 169 | pub struct PinThatsNCE; 170 | impl NCE for PinThatsNCE {} 171 | pub struct PinThatsNE1; 172 | impl NE1 for PinThatsNE1 {} 173 | pub struct PinThatsNE2; 174 | impl NE2 for PinThatsNE2 {} 175 | pub struct PinThatsNE3; 176 | impl NE3 for PinThatsNE3 {} 177 | pub struct PinThatsNE4; 178 | impl NE4 for PinThatsNE4 {} 179 | pub struct PinThatsNL; 180 | impl NL for PinThatsNL {} 181 | pub struct PinThatsNOE; 182 | impl NOE for PinThatsNOE {} 183 | pub struct PinThatsNWAIT; 184 | impl NWAIT for PinThatsNWAIT {} 185 | pub struct PinThatsNWE; 186 | impl NWE for PinThatsNWE {} 187 | pub struct PinThatsSDCKE0; 188 | impl SDCKE0 for PinThatsSDCKE0 {} 189 | pub struct PinThatsSDCKE1; 190 | impl SDCKE1 for PinThatsSDCKE1 {} 191 | pub struct PinThatsSDCLK; 192 | impl SDCLK for PinThatsSDCLK {} 193 | pub struct PinThatsSDNCAS; 194 | impl SDNCAS for PinThatsSDNCAS {} 195 | pub struct PinThatsSDNE0; 196 | impl SDNE0 for PinThatsSDNE0 {} 197 | pub struct PinThatsSDNE1; 198 | impl SDNE1 for PinThatsSDNE1 {} 199 | pub struct PinThatsSDNRAS; 200 | impl SDNRAS for PinThatsSDNRAS {} 201 | pub struct PinThatsSDNWE; 202 | impl SDNWE for PinThatsSDNWE {} 203 | -------------------------------------------------------------------------------- /tests/sdram_pin.rs: -------------------------------------------------------------------------------- 1 | //! Tests SDRAM pin constraints apply correctly 2 | 3 | mod dummy_pins; 4 | use dummy_pins::*; 5 | 6 | use stm32_fmc::*; 7 | 8 | /// Dummy FmcPeripheral implementation for testing 9 | struct DummyFMC; 10 | unsafe impl FmcPeripheral for DummyFMC { 11 | const REGISTERS: *const () = 0 as *const (); 12 | fn enable(&mut self) {} 13 | fn source_clock_hz(&self) -> u32 { 14 | 100_000_000 15 | } 16 | } 17 | 18 | macro_rules! fmc_pin_set { 19 | ($($p:ident),*) => { 20 | paste::item! { 21 | ( 22 | $( 23 | [< PinThats $p:upper>] {} 24 | ),* 25 | ) 26 | } 27 | } 28 | } 29 | 30 | #[test] 31 | /// SDRAM with 12 address pins, 4 banks 32 | fn sdram_pins_12a_4b() { 33 | let fmc = DummyFMC {}; 34 | let pins = fmc_pin_set!( 35 | // 12 address bits 36 | A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, 37 | // 4 internal banks -------------------------------------- 38 | BA0, BA1, 39 | // 32 bit data ------------------------------------------- 40 | D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, 41 | D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, 42 | D30, D31, 43 | // NBL0-3 ------------------------------------------------ 44 | NBL0, NBL1, NBL2, NBL3, 45 | // SDRAM Bank 0 ------------------------------------------ 46 | SDCKE0, SDCLK, SDNCAS, SDNE0, SDNRAS, SDNWE 47 | ); 48 | let chip = devices::is42s32800g_6::Is42s32800g {}; 49 | 50 | // Check we can create a SDRAM 51 | Sdram::new(fmc, pins, chip); 52 | } 53 | 54 | #[test] 55 | #[should_panic] 56 | /// SDRAM with 12 address pins, 4 banks 57 | fn sdram_pins_12a_4b_not_enough_adress_pins() { 58 | let fmc = DummyFMC {}; 59 | let pins = fmc_pin_set!( 60 | // 11 bit address (!) 61 | A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, 62 | // 4 internal banks -------------------------------------- 63 | BA0, BA1, 64 | // 32 bit data ------------------------------------------- 65 | D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, 66 | D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, 67 | D30, D31, 68 | // NBL0-3 ------------------------------------------------ 69 | NBL0, NBL1, NBL2, NBL3, 70 | // SDRAM Bank 0 ------------------------------------------ 71 | SDCKE0, SDCLK, SDNCAS, SDNE0, SDNRAS, SDNWE 72 | ); 73 | let chip = devices::is42s32800g_6::Is42s32800g {}; 74 | 75 | // Check we can create a SDRAM 76 | Sdram::new(fmc, pins, chip); 77 | } 78 | 79 | #[test] 80 | #[should_panic] 81 | /// SDRAM with 12 address pins, 4 banks 82 | fn sdram_pins_12a_4b_not_enough_bank_pins() { 83 | let fmc = DummyFMC {}; 84 | let pins = fmc_pin_set!( 85 | // 12 address bits 86 | A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, 87 | // 2 internal banks (!) ----------------------------------- 88 | BA0, 89 | // 32 bit data -------------------------------------------- 90 | D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, 91 | D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, 92 | D30, D31, 93 | // NBL0-3 ------------------------------------------------- 94 | NBL0, NBL1, NBL2, NBL3, 95 | // SDRAM Bank 0 ------------------------------------------- 96 | SDCKE0, SDCLK, SDNCAS, SDNE0, SDNRAS, SDNWE 97 | ); 98 | let chip = devices::is42s32800g_6::Is42s32800g {}; 99 | 100 | // Check we can create a SDRAM 101 | Sdram::new(fmc, pins, chip); 102 | } 103 | 104 | #[derive(Clone, Copy, Debug, PartialEq)] 105 | pub struct DummyChip {} 106 | 107 | const BURST_LENGTH_1: u16 = 0x0000; 108 | const BURST_TYPE_SEQUENTIAL: u16 = 0x0000; 109 | const CAS_LATENCY_3: u16 = 0x0030; 110 | const OPERATING_MODE_STANDARD: u16 = 0x0000; 111 | const WRITEBURST_MODE_SINGLE: u16 = 0x0200; 112 | 113 | impl SdramChip for DummyChip { 114 | const MODE_REGISTER: u16 = BURST_LENGTH_1 115 | | BURST_TYPE_SEQUENTIAL 116 | | CAS_LATENCY_3 117 | | OPERATING_MODE_STANDARD 118 | | WRITEBURST_MODE_SINGLE; 119 | 120 | const CONFIG: stm32_fmc::SdramConfiguration = SdramConfiguration { 121 | column_bits: 9, 122 | row_bits: 12, 123 | memory_data_width: 32, // 32-bit 124 | internal_banks: 4, // 4 internal banks 125 | cas_latency: 3, // CAS latency = 3 126 | write_protection: false, 127 | read_burst: true, 128 | read_pipe_delay_cycles: 0, 129 | }; 130 | 131 | const TIMING: stm32_fmc::SdramTiming = SdramTiming { 132 | startup_delay_ns: 100_000, // 100 µs 133 | max_sd_clock_hz: 100_000_000, // 100 MHz 134 | refresh_period_ns: 15_625, // 64ms / (4096 rows) = 15625ns 135 | mode_register_to_active: 2, // tMRD = 2 cycles 136 | exit_self_refresh: 7, // tXSR = 70ns 137 | active_to_precharge: 4, // tRAS = 42ns 138 | row_cycle: 7, // tRC = 70ns 139 | row_precharge: 2, // tRP = 18ns 140 | row_to_column: 2, // tRCD = 18ns 141 | }; 142 | } 143 | 144 | #[test] 145 | /// Test that we can implement the SdramChip trait 146 | fn sdram_chip_impl() { 147 | let fmc = DummyFMC {}; 148 | let pins = fmc_pin_set!( 149 | // 12 address bits 150 | A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, 151 | // 4 internal banks -------------------------------------- 152 | BA0, BA1, 153 | // 32 bit data ------------------------------------------- 154 | D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, 155 | D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, 156 | D30, D31, 157 | // NBL0-3 ------------------------------------------------ 158 | NBL0, NBL1, NBL2, NBL3, 159 | // SDRAM Bank 0 ------------------------------------------ 160 | SDCKE0, SDCLK, SDNCAS, SDNE0, SDNRAS, SDNWE 161 | ); 162 | let chip = DummyChip {}; 163 | 164 | // Check we can create a SDRAM 165 | Sdram::new(fmc, pins, chip); 166 | } 167 | --------------------------------------------------------------------------------