.. index:: bitfields why declare early ?, bitfields, configuration .. _bitfields-declare-early: BITFIELDS, DECLARE EARLY ? ========================== This article is an addition to my bitfield series: 1. :ref:`keil c v/s svd2forth` 2. :ref:`Bitfields and Structures` Why I Use and Declare Bitfields Early ------------------------------------- I believe there are two Forth styles: 1. Programmer Style ^^^^^^^^^^^^^^^^^^^ This style deals with Forth programming, is efficient, well written and easily understood. It's everything a Forth user appreciates. :: \ Memmap $40002800 constant RTC RTC $C + CONSTANT RTC_ISR RTC $10 + CONSTANT RTC_PRER \ Program Code : rtc-cal-set-on $80 RTC_ISR bis! BEGIN $40 RTC_ISR BIT@ UNTIL \ Calendar registers update is allowed. $7f00ff RTC_PRER ! \ From LSI, LSE - $ff $7f00ff RTC_PRER ! ; 2. My Electronics Technician Style ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ My style (below) looks like it was written by a bored programmer on Friday afternoon. It's longer than the code above and most programmers would want to factor out \ Bitfields below as much of it seems redundant to them. The Forth programmer mind simply cannot resist factoring everything into its most basic form. And that's a very good thing, a highly honed efficiency skill that is somewhat rare in a world of excess computing resources. Then why do I use *bitfields*, what information do they provide that the *Programmer Style* above does not ? The answer for the *impatient* is **HARDWARE INFORMATION** which it totally lacking in the Programmer Style above. Please permit me to explain below. :: \ Memmap $40002800 constant RTC RTC $C + CONSTANT RTC_ISR RTC $10 + CONSTANT RTC_PRER \ Bitfields \ RTC_ISR () Reset:0x00000007 : RTC_ISR_INIT ( -- x addr ) 7 bit RTC_ISR ; \ RTC_ISR_INIT, Initialization mode : RTC_ISR_INITF? ( -- x addr ) 6 bit RTC_ISR bit@ ; \ RTC_ISR_INITF, Initialization flag \ RTC_PRER (read-write) Reset:0x007F00FF : RTC_PRER_PREDIV_A ( %bbbbbbb -- x addr ) 16 lshift RTC_PRER ; \ RTC_PRER_PREDIV_A, Asynchronous prescaler factor : RTC_PRER_PREDIV_S ( %bbbbbbbbbbbbbbb -- x addr ) RTC_PRER ; \ RTC_PRER_PREDIV_S, Synchronous prescaler factor \ Program Code : rtc-cal-set-on RTC_ISR_INIT BIS! \ Enter RTC Initialization mode begin RTC_ISR_INITF? until \ Loop until Calendar has been initialized %1111111 RTC_PRER_PREDIV_A bis! \ Asynchronous prescaler factor %11111111 RTC_PRER_PREDIV_S bis! \ Synchronous prescaler factor ; Programmer Style Example ^^^^^^^^^^^^^^^^^^^^^^^^ In this example I use source from the Mecrisp-Stellaris user contributions to deconstruct a code segment and analyse the configuration of *hardware* involved. We can't see how it works without referring to the :download:`Technical Reference` for the MCU involved. This can be very time consuming especially if has to be done for every peripheral register used in the source. .. _programmer-style-code: :: $40002800 constant RTC RTC $C + CONSTANT RTC_ISR RTC $10 + CONSTANT RTC_PRER : rtc-cal-set-on $80 RTC_ISR bis! BEGIN $40 RTC_ISR BIT@ UNTIL \ Calendar registers update is allowed. $7f00ff RTC_PRER ! \ From LSI, LSE - $ff $7f00ff RTC_PRER ! ; Deconstructing the Programmer Style Example ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ $80 RTC_ISR bis! ~~~~~~~~~~~~~~~~ This means "set bit 7 of RTC_ISR". :: $80 bin. $00000080 3322222222221111111111 10987654321098765432109876543210 00000000000000000000000010000000 But *what IS bit7* ? We need to look in the Technical manual to find that out that *bit7* is the RTC *init mode* .. image:: pics/stm32f051/rtc_isr.jpg .. image:: pics/stm32f051/rtc_isr-2.jpg BEGIN $40 RTC_ISR BIT@ UNTIL ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This code reads bit 6 (INITF) of the RTC_ISR, looping until it is HIGH :: $40 bin. $00000040 3322222222221111111111 10987654321098765432109876543210 00000000000000000000000001000000 $7f00ff RTC_PRER ! ^^^^^^^^^^^^^^^^^^ Writes $7f00ff to the RTC_PRER *register*. But why *twice* ? :: $7f00ff RTC_PRER ! \ From LSI, LSE - $ff $7f00ff RTC_PRER ! RTC_PRER Register ~~~~~~~~~~~~~~~~~ .. image:: pics/stm32f051/rtc_prer.jpg The RTC_PRER register has two bitfields, "RTC_PRER_PREDIV_A" and "RTC_PRER_PREDIV_S". It's obvious the coder is writing both the RTC_PRER_PREDIV_A and RTC_PRER_PREDIV_S bitfields at the same time by writing to the RTC_PRER *register* with a CELL wide value. But why is this done TWICE ? It's because the RTC prescaler register (RTC_PRER) initialization must be performed in two separate write accesses, i.e. once for RTC_PRER_PREDIV_A and once for RTC_PRER_PREDIV_S Looking at the binary value being written into register RTC_PRER. One can see that the $7F part will be written to "RTC_PRER_PREDIV_A" and the $FF part to "RTC_PRER_PREDIV_S" at the same time. This is then done again to complete the required sequence. :: $7f00ff RTC_PRER ! \ From LSI, LSE - $ff $7f00ff bin. $007F00FF 3322222222221111111111 10987654321098765432109876543210 00000000011111110000000011111111 Electronics Technician Style ---------------------------- Otherwise known as "Declare Bitfields Early", this style uses bitfield definitions derived from the CMSIS-SVD file released by the manufacturer of the MCU and transformed by XSLT. The \ Bitfields paragraph contains vital hardware information, necessary for the easy maintenance of this code years later and possibly negating the requirement of having a :download:`Technical Reference` on hand ? The bitfield definitions tells me whether a bitfield is a single bit that requires setting, clearing or testing or whether it is a multi bit choice and how many bits there are. The comments field also provides a terse summary of the bitfield function. Finally the name of the bitfield definition is CMSIS-SVD compliant and can be used to search a technical reference PDF for more information. :: \ Memmap $40002800 constant RTC RTC $C + CONSTANT RTC_ISR RTC $10 + CONSTANT RTC_PRER \ Bitfields \ RTC_ISR () Reset:0x00000007 : RTC_ISR_INIT ( -- x addr ) 7 bit RTC_ISR ; \ RTC_ISR_INIT, Initialization mode : RTC_ISR_INITF? ( -- x addr ) 6 bit RTC_ISR bit@ ; \ RTC_ISR_INITF, Initialization flag \ RTC_PRER (read-write) Reset:0x007F00FF : RTC_PRER_PREDIV_A ( %bbbbbbb -- x addr ) 16 lshift RTC_PRER ; \ RTC_PRER_PREDIV_A, Asynchronous prescaler factor : RTC_PRER_PREDIV_S ( %bbbbbbbbbbbbbbb -- x addr ) RTC_PRER ; \ RTC_PRER_PREDIV_S, Synchronous prescaler factor \ Program Code : rtc-cal-set-on RTC_ISR_INIT BIS! \ Enter RTC Initialization mode begin RTC_ISR_INITF? until \ Loop until Calendar has been initialized %1111111 RTC_PRER_PREDIV_A bis! \ Asynchronous prescaler factor %11111111 RTC_PRER_PREDIV_S bis! \ Synchronous prescaler factor ; Summary ------- Embedded programmers have to worry about the hardware *and* the software, they are of equal importance, now when the program is written, and years later when it's maintained, upgraded or just repaired. Removing all the hardware information isn't *embedded programming*, it's just *programming*.