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¶
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’ <http://gema.sourceforge.net/new/index.shtml> .
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¶
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 ?
Peripheral Selection View¶
All the MCU (STM32F051) peripherals are in this list for easy choice.
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¶
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
See also
See also
See also
f0 disco lmt01 gema¶
Back to: f0 disco lmt01 gema
Or
Back to: Quadrature Rotary Switch