iMX6 Register Access - FrankBau/meta-marsboard-bsp GitHub Wiki

Direct register access from user space is a low level debugging aid and not intended for production code.

BoundaryDevices provides a nice little tool devregs which can read and write registers from user space in a convenient way. The source code is here https://github.com/boundarydevices/devregs and one could compile it on the target board, but there is also a bitbake recipe for it, which we want to use:

bitbake devregs

Pre-requisites: you have a working Yocto Build Environment installed on your build host, see Setting up the Build Environment.

Open a terminal and go to the top level folder of the Yocto Build Environment. This top level folder is referred to as $(BSPDIR). Goto the sources subfolder of $(BSPDIR). There are several subfolders for yocto layers like meta-marsboard-bsp etc.. In the sources folder, execute

git clone https://github.com/boundarydevices/meta-boundary.git

This creates a new subfolder meta-boundary parallel to the existing folders. Now, add the meta-boundary layer to the file $(BSPDIR)/build/conf/bblayers.conf using an editor. (build is the name of the build directory.)

Add a new line for layer /meta-boundary below meta-marsboard-bsp as follows:

...
BBLAYERS = " \
  ${BSPDIR}/sources/poky/meta \
  ${BSPDIR}/sources/poky/meta-yocto \
  \
  ${BSPDIR}/sources/meta-openembedded/meta-oe \
  ${BSPDIR}/sources/meta-openembedded/meta-multimedia \
  \
  ${BSPDIR}/sources/meta-fsl-arm \
  ${BSPDIR}/sources/meta-fsl-arm-extra \
  ${BSPDIR}/sources/meta-fsl-demos \
  ${BSPDIR}/sources/meta-marsboard-bsp \
  ${BSPDIR}/sources/meta-boundary \
"

(Depending on your project there may be more or less layers.)

In the terminal go to $(BSPDIR) and start a bitbake-shell.

source setup-environment build/

This sets ups the build environment and puts you in the build folder.

Now, among others, the devregs recipe (which is located in $(BSPDIR)/sources/meta-boundary/recipes-boundary/devregs/devregs.bb) is visible to bitbake.

Simply enter:

bitbake devregs

Which will build the devregs package and put the result to $(BSPDIR)//build/tmp/deploy/rpm/cortexa9hf_vfp_neon/devregs-1.0*.rpm

You may later add devregs to your favorite image such that is automatically included in your image.

Copy the .rpm package to the MarS Board (see Exchanging-files-with-MarS-Board) and install it on the board:

root@marsboard:~# rpm -i devregs-1.0*.rpm 

Using devregs

Danger zone! devregs uses raw reads/writes to the iMX6 memory mapped registers. Improper use may crash or even damage your board. E.g. is hangs the system when called without a command line parameter, grrh!

For a first test, you may read the general purpose timer count register which is continuously incrementing, so each read gives you a larger (mod 2^32) value, for example:

root@marsboard:~# devregs GPT_CNT          (                                      
GPT_CNT:0x02098024      =0xa3be31f2                                             
root@marsboard:~# devregs GPT_CNT                                               
GPT_CNT:0x02098024      =0xa3d8487d  

read and write a GPIO

Now, we want to read/write a GPIO. For example we use the User LED on Mars Board (the green LED in the middle of the three on-board LEDs) which is connected to GPIO group 5 bit 2 (GPIO5_IO02). For reference, check the iMX6 technical reference manual (IMX6DQRM.pdf) for GPIO5_IO02.

This shows that this GPIO is available as ALT5 function of pad EIM_ADDR25 which is confgured in register IOMUXC_SW_MUX_CTL_PAD_EIM_ADDR25. Unfortunately, the register names slightly differ between the reference manual and devregs. Consult the devregs data base which is located online at https://github.com/boundarydevices/devregs/blob/master/dat/devregs_imx6q.dat (or locally on your board in /etc/devregs*.dat):

It turns out, that devregs uses the name IOMUXC_SW_MUX_CTL_PAD_EIM_A25, lets read it:

root@marsboard:~# devregs IOMUXC_SW_MUX_CTL_PAD_EIM_A25                         
IOMUXC_SW_MUX_CTL_PAD_EIM_A25:0x020e0088        =0x00000005 

Okay, pad function ALT5 is already set. Now, lets switch on the LED. The reference manual shows that the following registers control GPIO group 5:

20A_C000 GPIO data register (GPIO5_DR) 
20A_C004 GPIO direction register (GPIO5_GDIR) 
20A_C008 GPIO pad status register (GPIO5_PSR) 

Lets check the GPIO direction (input/output):

root@marsboard:~# devregs GPIO5_GDIR                                            
GPIO5_GDIR:0x020ac004   =0x00000004  

GPIO5_IO02 is bit 2 which is 1. 1 stands for output, okay.

The output is low active, so write a 0 to bit 2 (IO02) of GPIO5_DR:

root@marsboard:~# devregs GPIO5_DR 0x00000000                                   
GPIO5_DR:0x020ac000     =0xcfffffe4                                             
GPIO5_DR:0x020ac000 == 0xcfffffe4...0x00000000

This switches the User LED on and

root@marsboard:~# devregs GPIO5_DR 0x00000004                                   
GPIO5_DR:0x020ac000     =0xcfffffe0                                             
GPIO5_DR:0x020ac000 == 0xcfffffe0...0x00000004      

is switching the User LED off again!

Last, lets check the electrical configuration of the pad which is in IOMUXC_SW_PAD_CTL_PAD_EIM_A25 (in the reference manual: IOMUXC_SW_PAD_CTL_PAD_EIM_ADDR25)

root@marsboard:~# devregs IOMUXC_SW_PAD_CTL_PAD_EIM_A25                         
IOMUXC_SW_PAD_CTL_PAD_EIM_A25:0x020e039c        =0x0000b0b1 

For the interpretation of the individual bits you should consult the technical refernce manual or read iMX6 Pad Mux and Pad Control.

Further reading: