1 //***************************************************************************** 2 // 3 // am_reg_macros.h 4 //! @file 5 //! 6 //! @brief Helper macros for using hardware registers. 7 // 8 //***************************************************************************** 9 10 //***************************************************************************** 11 // 12 // Copyright (c) 2017, Ambiq Micro 13 // All rights reserved. 14 // 15 // Redistribution and use in source and binary forms, with or without 16 // modification, are permitted provided that the following conditions are met: 17 // 18 // 1. Redistributions of source code must retain the above copyright notice, 19 // this list of conditions and the following disclaimer. 20 // 21 // 2. Redistributions in binary form must reproduce the above copyright 22 // notice, this list of conditions and the following disclaimer in the 23 // documentation and/or other materials provided with the distribution. 24 // 25 // 3. Neither the name of the copyright holder nor the names of its 26 // contributors may be used to endorse or promote products derived from this 27 // software without specific prior written permission. 28 // 29 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 30 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 33 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 34 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 35 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 36 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 37 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 39 // POSSIBILITY OF SUCH DAMAGE. 40 // 41 // This is part of revision 1.2.11 of the AmbiqSuite Development Package. 42 // 43 //***************************************************************************** 44 45 #ifndef AM_REG_MACROS_H 46 #define AM_REG_MACROS_H 47 48 #ifdef __cplusplus 49 extern "C" 50 { 51 #endif 52 53 //***************************************************************************** 54 // 55 // Include the inline assembly macros. 56 // 57 //***************************************************************************** 58 #include "am_reg_macros_asm.h" 59 60 //***************************************************************************** 61 // 62 // High-level Helper Macros. 63 // 64 // Usage: 65 // 66 // For direct 32-bit access to a register, use AM_REGVAL: 67 // AM_REGVAL(REG_VCOMP_BASEADDR + AM_VCOMP_VCMPCFG_O) |= 0xDEADBEEF; 68 // 69 // The AM_REG macro can also be used as a shorthand version of AM_REGVAL: 70 // AM_REG(VCOMP, VCMPCFG) |= 0xDEADBEEF; 71 // 72 // The AM_REGn macro is used for accessing registers of peripherals with 73 // multiple instances, such as IOMSTR. 74 // AM_REGn(IOMSTR, 1, CLKCFG) |= 0xDEADBEEF; 75 // 76 // To write to a specific bitfield within a register, use AM_BFW or AM_BFWn: 77 // AM_BFW(CTIMER, 0, CTCTRL0, TMRB0FN, 0x3); 78 // 79 // To read a field, use AM_BFR or AM_BFRn: 80 // ui32Timer0Fn = AM_BFR((CTIMER, 0, CTCTRL0, TMRB0FN); 81 // 82 // Note: 83 // 84 // AM_REGn, AM_BFW and AM_BFR are concatenation-based, which means that 85 // standalone macro definitions should not be used for the 'module', 'reg', and 86 // 'field' arguments.All macro names in the various peripheral header files are 87 // written in one of the following forms: 88 // - AM_REG_##module_reg_O 89 // - AM_REG_##module_reg_field_S 90 // - AM_REG_##module_reg_field_M 91 // 92 // The "module", "reg" and "field" fragments may be used as valid arguments to 93 // the AM_REGn, AM_BFW, and AM_BFR macros, all of which are able to perform the 94 // necessary concatenation operations to reconstruct the full macros and look 95 // up the appropriate base address for the instance number given. For 96 // peripherals with only one instance, use instance number 0. 97 // 98 // The AM_REGVAL macro does not perform any concatenation operations, so the 99 // complete macro name (including any suffix) must be specified. 100 // 101 //***************************************************************************** 102 #define AM_REGVAL(x) (*((volatile uint32_t *)(x))) 103 #define AM_REGVAL_FLOAT(x) (*((volatile float *)(x))) 104 105 //***************************************************************************** 106 // 107 // Register access macros for single-instance modules 108 // AM_REG - Write a register of a module. 109 // AM_BFW - Write a value to a bitfield of a register. 110 // AM_BFWe - Use a defined enum value to write a value to a register bitfield. 111 // AM_BFR - Read a bitfield value from a register. 112 // AM_BFM - Read and mask a bitfield from a register, but leave the value in 113 // its bit position. Useful for comparing with enums. 114 // 115 // AM_BFV - Move a value to a bitfield. This macro is used for creating a 116 // value, it does not modify any register. 117 // AM_BFX - Extract the value of a bitfield from a 32-bit value, such as that 118 // read from a register. Does not read or modify any register. 119 // 120 //***************************************************************************** 121 #define AM_REG(module, reg) \ 122 AM_REGn(module, 0, reg) 123 124 #define AM_BFW(module, reg, field, value) \ 125 AM_BFWn(module, 0, reg, field, value) 126 127 #define AM_BFWe(module, reg, field, enumval) \ 128 AM_BFWen(module, 0, reg, field, enumval) 129 130 #define AM_BFR(module, reg, field) \ 131 AM_BFRn(module, 0, reg, field) 132 133 #define AM_BFM(module, reg, field) \ 134 AM_BFMn(module, 0, reg, field) 135 136 #define AM_BFV(module, reg, field, value) \ 137 (((uint32_t)(value) << AM_REG_##module##_##reg##_##field##_S) & \ 138 AM_REG_##module##_##reg##_##field##_M) 139 140 #define AM_BFX(module, reg, field, value) \ 141 (((uint32_t)(value) & AM_REG_##module##_##reg##_##field##_M) >> \ 142 AM_REG_##module##_##reg##_##field##_S) 143 144 145 //***************************************************************************** 146 // 147 // Register access macros for multi-instance modules 148 // AM_REGADDRn - Calc the register address inside a multiple instance module. 149 // AM_REGn - Write a register of a multiple instance module. 150 // AM_BFWn - Write a value to a bitfield of a register in a multiple instance. 151 // AM_BFWen - Use a defined enum value to write a value to a bitfield of a 152 // register in a multiple instance. 153 // AM_BFRn - Read a bitfield value from a register in a multiple instance. 154 // AM_BFMn - Read and mask a bitfield, but leave the value in its bit position. 155 // (Useful for comparing with enums.) 156 // 157 //***************************************************************************** 158 #define AM_REGADDRn(module, instance, reg) \ 159 (AM_REG_##module##n(instance) + AM_REG_##module##_##reg##_O) 160 161 #define AM_REGn(module, instance, reg) \ 162 AM_REGVAL(AM_REG_##module##n(instance) + AM_REG_##module##_##reg##_O) 163 164 #define AM_BFWn(module, instance, reg, field, value) \ 165 AM_REGn(module, instance, reg) = \ 166 (AM_BFV(module, reg, field, value) | \ 167 (AM_REGn(module, instance, reg) & \ 168 (~AM_REG_##module##_##reg##_##field##_M))) 169 170 #define AM_BFWen(module, instance, reg, field, enumval) \ 171 AM_REGn(module, instance, reg) = \ 172 (AM_REG_##module##_##reg##_##field##_##enumval | \ 173 (AM_REGn(module, instance, reg) & \ 174 (~AM_REG_##module##_##reg##_##field##_M))) 175 176 #define AM_BFRn(module, instance, reg, field) \ 177 AM_BFX(module, reg, field, AM_REGn(module, instance, reg)) 178 179 #define AM_BFMn(module, instance, reg, field) \ 180 (AM_REGn(module, instance, reg) & AM_REG_##module##_##reg##_##field##_M) 181 182 //***************************************************************************** 183 // 184 // "Atomic" register access macros - use when a read-modify-write is required. 185 // 186 // These macros will be slower than the normal macros, but they will also 187 // guarantee threadsafe hardware access. 188 // 189 // These macros require a nesting-friendly critical section implementation. If 190 // you are using the HAL, you can use the default definitions below. If not, 191 // you will need to supply your own. 192 // 193 // Atomic register access macros usage: 194 // AM_REGa - Write a register of a single instance module. Provide operator 195 // (&,|,etc) to perform that operation on the reg using value, or 196 // no operator to simply write the value atomically. 197 // AM_REGa_SET - Set bits in a single instance module according to the mask. 198 // AM_REGa_CLR - Clear bits in a single instance module according to the mask. 199 // AM_REGan - Multiple module version of AM_REGa. 200 // AM_REGan_SET - Multiple instance version of AM_REGa_SET. 201 // AM_REGan_CLR - Multiple instance version of AM_REGa_CLR. 202 // AM_BFWa - Write a value to a register bitfield. 203 // AM_BFWae - Use a defined enum value to write a value to a bitfield. 204 // AM_BFWan - Write a value to a bitfield of a register in a multiple instance. 205 // AM_BFWaen - Use a defined enum value to write a value to a bitfield of a 206 // register in a multiple instance. 207 // 208 //***************************************************************************** 209 #ifndef AM_CRITICAL_BEGIN 210 #define AM_CRITICAL_BEGIN uint32_t ui32Primask = am_hal_interrupt_master_disable() 211 #define AM_CRITICAL_END am_hal_interrupt_master_set(ui32Primask) 212 #endif 213 214 #define AM_REGan(module, instance, reg, operator, value) \ 215 AM_CRITICAL_BEGIN_ASM \ 216 AM_REGn(module, instance, reg) operator##= (value); \ 217 AM_CRITICAL_END_ASM 218 219 #define AM_REGan_SET(module, instance, reg, mask) \ 220 AM_CRITICAL_BEGIN_ASM \ 221 AM_REGn(module, instance, reg) |= (mask); \ 222 AM_CRITICAL_END_ASM 223 224 #define AM_REGan_CLR(module, instance, reg, mask) \ 225 AM_CRITICAL_BEGIN_ASM \ 226 AM_REGn(module, instance, reg) &= (~mask); \ 227 AM_CRITICAL_END_ASM 228 229 #define AM_REGa(module, reg, operator, value) \ 230 AM_REGan(module, 0, reg, operator, value) 231 232 #define AM_REGa_CLR(module, reg, mask) \ 233 AM_REGan_CLR(module, 0, reg, mask) 234 235 #define AM_REGa_SET(module, reg, mask) \ 236 AM_REGan_SET(module, 0, reg, mask) 237 238 #define AM_BFWa(module, reg, field, value) \ 239 AM_CRITICAL_BEGIN_ASM \ 240 AM_BFW(module, reg, field, value); \ 241 AM_CRITICAL_END_ASM 242 243 #define AM_BFWae(module, reg, field, enumval) \ 244 AM_CRITICAL_BEGIN_ASM \ 245 AM_BFWe(module, reg, field, enumval); \ 246 AM_CRITICAL_END_ASM 247 248 #define AM_BFWan(module, instance, reg, field, value) \ 249 AM_CRITICAL_BEGIN_ASM \ 250 AM_BFWn(module, instance, reg, field, enumval); \ 251 AM_CRITICAL_END_ASM 252 253 #define AM_BFWaen(module, instance, reg, field, enumval) \ 254 AM_CRITICAL_BEGIN_ASM \ 255 AM_BFWen(module, instance reg, field, enumval); \ 256 AM_CRITICAL_END_ASM 257 258 //***************************************************************************** 259 // 260 // Other helper Macros. 261 // 262 // Note: These macros make use of macro concatenation, so the '_S' or '_M' 263 // suffix on a register bitfield macro should not be supplied by the user. 264 // The macro will apply each suffix as needed. 265 // 266 //***************************************************************************** 267 268 // 269 // AM_ENUMX extracts a register bitfield enumeration to the bit 0 position, 270 // which makes it possible to use enums directly with existing macros such 271 // as AM_BFR() or AM_BFW(). 272 // Brief overview: bitfield enumerations are pre-shifted such that the defined 273 // value lines up with the bitfield. This is convenient for many operations, 274 // but not so when using AM_BFR() to read the value of a register bitfield 275 // as AM_BFR() shifts the bitfield value to the bit 0 position. 276 // Note that this type of bitfield extraction is Cortex efficient via the 277 // UBFX (unsigned bit field extract) instruction. 278 // 279 // Alternately, AM_BFM() can also be used. AM_BFM() reads a register and masks 280 // the bitfield value (without shifting), thereby allowing direct comparison 281 // with a defined enum. 282 // 283 // Examples: 284 // if ( AM_BFR(CLKGEN, CCTRL, CORESEL) == 285 // AM_ENUMX(CLKGEN, CCTRL, CORESEL, HFRC) ) 286 // 287 // or alternatively: 288 // if ( AM_BFM(CLKGEN, CCTRL, CORESEL) == AM_REG_CLKGEN_CCTRL_CORESEL_HFRC ) 289 // 290 #define AM_ENUMX(module, reg, field, enumname) \ 291 ((AM_REG_##module##_##reg##_##field##_##enumname) >> \ 292 (AM_REG_##module##_##reg##_##field##_S)) 293 294 // 295 // AM_WRITE_SM performs a shift/mask operation to prepare the value 'x' to be 296 // written to the register field 'field'. 297 // 298 // For example: 299 // AM_REGVAL(ui32Base + AM_VCOMP_VCMP_CFG_O) |= 300 // AM_WRITE_SM(AM_VCOMP_VCMP_CFG_LVLSEL, ui32Value); 301 // 302 #define AM_WRITE_SM(field, x) (((x) << field##_S) & field##_M) 303 304 // 305 // AM_READ_SM performs a shift/mask operation to make it easier to interpret 306 // the value of a given bitfield. This is essentially the reverse of the 307 // AM_WRITE_SM operation. In most cases, you will want to use the shorter 308 // AM_BFR macro instead of this one. 309 // 310 // For example: 311 // ui32Value = AM_READ_SM(AM_VCOMP_VCMP_CFG_NSEL, 312 // AM_REGVAL(ui32Base + AM_VCOMP_VCMP_CFG_O)); 313 // 314 #define AM_READ_SM(field, x) (((x) & field##_M) >> field##_S) 315 316 #ifdef __cplusplus 317 } 318 #endif 319 320 #endif // AM_REG_MACROS_H 321 322