.. index:: bitfields .. _bitfields: Bitfields ========= .. warning:: This page is for embedded Forth people, others may find it far too esoteric. A Word about Bitfields ---------------------- Non embedded programmers generally don't think in terms of bitfields because neat word or byte boundaries are the norm in their world. Embedded C programmers normally get their bitfields bundled up in structures organised by functionality. I.e. a disparate collection of bitfields from a number of different registers become a GPIO structure and so on. I do my embedded programming using *bitfields* and group them by register. Furthermore I also pre-process the bitfields so that their names assist comprehension and maintenance. It's true that the bitfields are just BITs but there are different ways of interpreting them. Some ways are a maintainers nightmare and help spread the (untrue) rumour that Forth is 'read only'. While Forth source can easily be written as 'read only' so can any other language, here are some examples. .. _write-only-code: Write Only Code --------------- This source code works, but it's very painful and tedious to decode. You need the Technical Reference Manual and a hex calculator at hand. There is no way to tell what it's doing just by reading it. It does however compile into the most compact code. :: $40000 $40021014 bis! 1 $48000400 bis! $C $48000400 bis! This code example was derived from the 'Better Code' example below, the register names were replaced by their hex address. Better Code ----------- This code sample uses register names, which increases comprehension and maintenance enormously, it also requires preloading all register hex addresses. Because bitfield names are not used, the Technical Reference Manual is again required to understand this code. :: constant $40021014 RCC_AHBENR constant $48000400 GPIOB_MODE \ Enable GPIOB peripheral clock, set pin PB0 as led output (push-pull) and set PB1 as analog input %1 18 lshift RCC_AHBENR bis! %01 GPIOB_MODER bis! %11 2 lshift GPIOB_MODER bis! Svd2forth-v6 ------------ This source has the same functionality as above, but uses Svd2forth-v6. There is no need for constants or bitfields to be predefined as this is done automatically when the source is read and a 'includes.fs' file containing these dependencies is created. This is uploaded before this source. This is done using the *Gema 'preprocessor'* . The register and bitfields only need be named in the source. Source ^^^^^^ :: RCC_AHBENR_IOPBEN RCC_AHBENR bis! \ enable GPIOB peripheral clock OUTPUT GPIOB_MODER_MODER0<< \ set PB0 to OUTPUT ANALOG GPIOB_MODER_MODER1<< \ set PB1 to ANALOG + GPIOB_MODER bis! Includes.fs ^^^^^^^^^^^ Preloaded automatically before the source is loaded. :: $40021014 constant RCC_AHBENR $48000400 constant GPIOB_MODER : GPIOB_MODER_MODER0<< ( %2 -- x ) ; \ rw","2","0","Port x configuration bits y = 0..15 : GPIOB_MODER_MODER1<< ( %2 -- x ) 2 lshift ; \ rw","2","2","Port x configuration bits y = 0..15 Where further technical assistance is needed, the includes.fs file offers more bitfield information such as stack diagram, bitfield access-type (read-write, etc), bitfield Width and Offset, and description. Intelligent Processing ---------------------- Svd2forth-V6 uses a combination of 'access type', 'bitWidth' and 'bitOffset' to intelligently optimise each bitfield action as tabled below. This is still under construction @ Jul 2021 ======== ======== ============ ============== =============================================== =================================== ================================================ Suffix Access? bitW, bitOff Stack Comment Example Comment Automatic Word Action ======== ======== ============ ============== =============================================== =================================== ================================================ << rw bw 2, bo 30 ( %2 -- x ) ANALOG GPIOB_MODER_MODER15<< GPIOB_MODER BIS! Set PB15 to ANALOG (%11) 30 lshift ? ro bw 1, bo 25 ( -- 1|0 ) DO RCC_CR_PLLRDY? LOOP Wait until PLLRDY is set 1 25 lshift RCC_CR bit@ ! wo bw 1, bo 31 ( -- ) GPIOF_BSRR_BR15! Reset PF15 1 31 lshift GPIOF_BSRR ! @ rw bw 2, bo 2 ( -- x ) RCC_CFGR_SWS@ fetch System Clock Switch Status 2 bitwidthmask 2 lshift RCC_CFGR @ and 2 rshift ======== ======== ============ ============== =============================================== =================================== ================================================ Bitfield Viewer --------------- This is a preview of my prototype Bitfield Viewer and select tool. The aim was to make a easy to use Bitfield viewer that can preselect any peripheral and then easily scroll to find the right bitfield before copying it to the programmers source. The bitfield data resides in a Sqlite3 database built automatically by swd2forth-v6, which means any client that can read Sqlite3 databases can use it. In this picture the reader is https://github.com/inloop/sqlite-viewer Visual Simplification ^^^^^^^^^^^^^^^^^^^^^ Understanding Cortex-M peripheral registers and bitfields can be daunting because of their abundance, so the Bitfield Viewer was also designed to present this information in a simpler way. * By selecting one peripheral at a time to reduce visual noise. * listing the number of *rows* in a peripheral. Apart from the "Reset Value" *row* at start of each register, all the other *rows* are bitfields. For instance TIM6 has *22 rows*, but TIM1 has *150*, so straight away you can see which is the more complex timer. Tim6 Peripheral View ^^^^^^^^^^^^^^^^^^^^ .. image:: projects/blink-f0disco-gdbtui/pics/bitfield-viewer-tim6-sml.jpg Cli Input Selections ^^^^^^^^^^^^^^^^^^^^ Prefer a CLI method ? :: sqlite3 bitfields.db ".mode column" ".headers on" ".width 25 22 20 6 6 6 40" "SELECT * FROM tim6" name stack word access bitwid bitoff description ------------------------- ---------------------- -------------------- ------ ------ ------ ---------------------------------------- Basic-timers - - - - - - TIM6_CR1 Reset Value $0000 - - - - - TIM6_CR1_ARPE ( -- x ) 1 7 lshift rw 1 7 Auto-reload preload enable TIM6_CR1_OPM ( -- x ) 1 3 lshift rw 1 3 One-pulse mode TIM6_CR1_URS ( -- x ) 1 2 lshift rw 1 2 Update request source TIM6_CR1_UDIS ( -- x ) 1 1 lshift rw 1 1 Update disable TIM6_CR1_CEN ( -- 1 ) 1 rw 1 0 Counter enable TIM6_CR2 Reset Value $0000 - - - - - TIM6_CR2_MMS<< ( %3 -- x ) 4 lshift rw 3 4 Master mode selection TIM6_DIER Reset Value $0000 - - - - - TIM6_DIER_UDE ( -- x ) 1 8 lshift rw 1 8 Update DMA request enable TIM6_DIER_UIE ( -- 1 ) 1 rw 1 0 Update interrupt enable TIM6_SR Reset Value $0000 - - - - - TIM6_SR_UIF ( -- 1 ) 1 rw 1 0 Update interrupt flag TIM6_EGR Reset Value $0000 - - - - - TIM6_EGR_UG! ( -- ) 1 TIM6_EGR bis! wo 1 0 Update generation TIM6_CNT Reset Value $00000000 - - - - - TIM6_CNT_CNT<< ( %16 -- x ) rw 16 0 Low counter value TIM6_PSC Reset Value $0000 - - - - - TIM6_PSC_PSC<< ( %16 -- x ) rw 16 0 Prescaler value TIM6_ARR Reset Value $00000000 - - - - - TIM6_ARR_ARR<< ( %16 -- x ) rw 16 0 Low Auto-reload value IWDG Peripheral View ^^^^^^^^^^^^^^^^^^^^ How complex is the Watchdog peripheral ? .. image:: projects/blink-f0disco-gdbtui/pics/svd2forth-v6-bitfields-database-viewer2-sml.jpg Peripheral Selection View ^^^^^^^^^^^^^^^^^^^^^^^^^ All the MCU (STM32F051) peripherals are in this list for easy choice. .. image:: projects/blink-f0disco-gdbtui/pics/svd2forth-v6-bitfields-database-viewer-sml.jpg Perhaps you prefer the CLI ? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: % sqlite3 bitfields.db SQLite version 3.26.0 2018-12-01 12:34:55 Enter ".help" for usage hints. sqlite> .tables ADC DAC Flash GPIOD I2C2 RCC SYSCFG TIM16 TIM6 WWDG CEC DBGMCU GPIOA GPIOE IWDG RTC TIM1 TIM17 TSC COMP DMA GPIOB GPIOF NVIC SPI1 TIM14 TIM2 USART1 CRC EXTI GPIOC I2C1 PWR SPI2 TIM15 TIM3 USART2 sqlite> .mode column sqlite> .width 15 15 15 4 2 2 50 sqlite> SELECT * FROM 'TIM1' LIMIT 0,30 ; Advanced-timer - - - - - - TIM1_CR1 Reset Value $0 - - - - - TIM1_CR1_CKD<< ( %2 -- x ) 8 lshift rw 2 8 Clock division TIM1_CR1_ARPE ( -- x ) 1 7 lshift rw 1 7 Auto-reload preload enable TIM1_CR1_CMS<< ( %2 -- x ) 5 lshift rw 2 5 Center-aligned mode selection TIM1_CR1_DIR ( -- x ) 1 4 lshift rw 1 4 Direction TIM1_CR1_OPM ( -- x ) 1 3 lshift rw 1 3 One-pulse mode TIM1_CR1_URS ( -- x ) 1 2 lshift rw 1 2 Update request source TIM1_CR1_UDIS ( -- x ) 1 1 lshift rw 1 1 Update disable TIM1_CR1_CEN ( -- 1 ) 1 rw 1 0 Counter enable TIM1_CR2 Reset Value $0 - - - - - TIM1_CR2_OIS4 ( -- x ) 1 14 lshift rw 1 14 Output Idle state 4 TIM1_CR2_OIS3N ( -- x ) 1 13 lshift rw 1 13 Output Idle state 3 TIM1_CR2_OIS3 ( -- x ) 1 12 lshift rw 1 12 Output Idle state 3 TIM1_CR2_OIS2N ( -- x ) 1 11 lshift rw 1 11 Output Idle state 2 TIM1_CR2_OIS2 ( -- x ) 1 10 lshift rw 1 10 Output Idle state 2 TIM1_CR2_OIS1N ( -- x ) 1 9 lshift rw 1 9 Output Idle state 1 TIM1_CR2_OIS1 ( -- x ) 1 8 lshift rw 1 8 Output Idle state 1 TIM1_CR2_TI1S ( -- x ) 1 7 lshift rw 1 7 TI1 selection TIM1_CR2_MMS<< ( %3 -- x ) 4 lshift rw 3 4 Master mode selection TIM1_CR2_CCDS ( -- x ) 1 3 lshift rw 1 3 Capture/compare DMA selection TIM1_CR2_CCUS ( -- x ) 1 2 lshift rw 1 2 Capture/compare control update selection TIM1_CR2_CCPC ( -- 1 ) 1 rw 1 0 Capture/compare preloaded control TIM1_SMCR Reset Value $0 - - - - - TIM1_SMCR_ETP ( -- x ) 1 15 lshift rw 1 15 External trigger polarity TIM1_SMCR_ECE ( -- x ) 1 14 lshift rw 1 14 External clock enable TIM1_SMCR_ETPS ( %2 -- x ) 12 lshift rw 2 12 External trigger prescaler TIM1_SMCR_ETF< ( %4 -- x ) 8 lshift rw 4 8 External trigger filter TIM1_SMCR_MSM ( -- x ) 1 7 lshift rw 1 7 Master/Slave mode TIM1_SMCR_TS<< ( %3 -- x ) 4 lshift rw 3 4 Trigger selection Search ^^^^^^ :: sqlite> SELECT * FROM 'TIM1' WHERE description LIKE 'Trig%'; TIM1_SMCR_TS<< ( %3 -- x ) 4 lshift rw 3 4 Trigger selection TIM1_DIER_TDE ( -- x ) 1 14 lshift rw 1 14 Trigger DMA request enable TIM1_DIER_TIE ( -- x ) 1 6 lshift rw 1 6 Trigger interrupt enable TIM1_SR_TIF ( -- x ) 1 6 lshift rw 1 6 Trigger interrupt flag TIM1_EGR_TG! ( -- ) 1 6 lshift TIM wo 1 6 Trigger generation Search Gui ^^^^^^^^^^ .. image:: projects/blink-f0disco-gdbtui/pics/sqlite-gui-search-sml.jpg Search ^^^^^^ :: .mode column .width 20 15 15 4 2 2 50 sqlite> SELECT * FROM 'RCC' WHERE name LIKE '%APB1ENR%'; RCC_APB1ENR Reset Value $0 - - - - - RCC_APB1ENR_TIM2EN ( -- 1 ) 1 rw 1 0 Timer 2 clock enable RCC_APB1ENR_TIM3EN ( -- x ) 1 1 lshift rw 1 1 Timer 3 clock enable RCC_APB1ENR_TIM6EN ( -- x ) 1 4 lshift rw 1 4 Timer 6 clock enable RCC_APB1ENR_TIM14EN ( -- x ) 1 8 lshift rw 1 8 Timer 14 clock enable RCC_APB1ENR_WWDGEN ( -- x ) 1 11 lshift rw 1 11 Window watchdog clock enable RCC_APB1ENR_SPI2EN ( -- x ) 1 14 lshift rw 1 14 SPI 2 clock enable RCC_APB1ENR_USART2E ( -- x ) 1 17 lshift rw 1 17 USART 2 clock enable RCC_APB1ENR_I2C1EN ( -- x ) 1 21 lshift rw 1 21 I2C 1 clock enable RCC_APB1ENR_I2C2EN ( -- x ) 1 22 lshift rw 1 22 I2C 2 clock enable RCC_APB1ENR_PWREN ( -- x ) 1 28 lshift rw 1 28 Power interface clock enable RCC_APB1ENR_DACEN ( -- x ) 1 29 lshift rw 1 29 DAC interface clock enable RCC_APB1ENR_CECEN ( -- x ) 1 30 lshift rw 1 30 HDMI CEC interface clock enable .. seealso:: :ref:`PLANG` .. seealso:: :ref:`Plang for STM32F103C8` .. seealso:: :ref:`PLANG Reader` f0 disco lmt01 gema ------------------- Back to: :ref:`f0 disco lmt01 gema` Or Back to: :ref:`Quadrature Rotary Switch`