• 0
Sign in to follow this  
kadionik

How to use I2C modules under embedded Linux for MicroBlaze

Question

Hi all,

This is a quick and dirty howto. This howto describes how to use I2C modules (onboard and through PMOD connector) under embedded Linux.

I've chosen to build my own Linux distro based on Linux kernel source for MicroBlaze softcore and busybox project for the init RAM DISK.

My board is the Nexys4 DDR board. If you respect the following requirements for the HW design compatible with Linux, you can use Petalinux too.

HW Vivado requirements (according to Xilinx UG1144) design to boot Linux:

  • MicroBlaze with MMU support by selecting either Linux with MMU or Low-end Linux with MMU configuration template in the MicroBlaze configuration wizard.
  • External memory controller with at least 32 MB of memory.
  • Dual channel timer with interrupt connected.
  • UART with interrupt connected.
  • Ethernet with interrupt connected.

Note that all peripherals you use must be interrupt capable. For the UART peripheral, if you have not enabled interrupts, you have no Linux console outputs.

For the Nexys4 DDR, you can follow this online tutorial: https://reference.digilentinc.com/learn/programmable-logic/tutorials/nexys-4-ddr-getting-started-with-microblaze-servers/start

At this stage, for the Nexys4 DDR board, you can add the onboard i2C temperature sensor (ADT7420) that uses the AXI IIC IP block.

I've added a second external temperature sensor (PMOD TMP3) connected to PMOD JA pins of the Nexys4 DDR board.

I've chosen to connect SCL TMP3 pin to JA1 PMOD JA pin (C17 FPGA pin) and SDA MP3 pin to JA2 PMOD JA pin (D18 FPGA pin). You connect GND and 3V3 pins from PMOD JA connector to corresponding TMP3 pins. You have finally 4 pins to connect.

You obtain the Vivado design shown below. Notice that both AXI IIC IP blocks have interrupts connected for Linux compatibility.

 

For the TMP3 sensor, I have an external port named temp3_sensor. I've created a XDC file containing:

set_property -dict { PACKAGE_PIN D5    IOSTANDARD LVCMOS33 } [get_ports { eth_ref_clk }]; # Sch=eth_ref_clk 

set_property -dict { PACKAGE_PIN C17    IOSTANDARD LVCMOS33 } [get_ports { tmp3_sensor_scl_io }]; 
set_property -dict { PACKAGE_PIN D18    IOSTANDARD LVCMOS33 } [get_ports { tmp3_sensor_sda_io }]; 

 

You can see that:

  • tmp3_sensor_scl_io signal is for SCL I2C signal.
  • tmp3_sensor_sda_io signal is for SDA I2C signal

Please respect notation: xxx external I2C port gives xxx_scl_io  and xxx_sda_io signal names in the XDC file.

Generate .bit file. Launch Vivado SDK tool, install the device tree plugin and generate Device Tree files. You can follow this link: https://numato.com/kb/neso-microblaze-linux-run-linux-neso-artix-7-fpga-module/

Copy the generated pl.dtsi file (under project_1/project_1.sdk/device_tree_bsp_0/ directory) into arch/microblaze/boot/dts/ Linux directory. Use the generated system-top.dts file (under project_1/project_1.sdk/device_tree_bsp_0/ directory) to create the xilinx.dts file into arch/microblaze/boot/dts/ Linux directory.

 

Be carefull with stdout options in the xilinx.dts file if you want Linux output enabled. Mine is:

/dts-v1/;
/include/ "pl.dtsi"
/ {
	chosen {
		bootargs = "console=ttyUL0,9600";
		linux,stdout-path = &axi_uartlite_0;
		stdout-path = &axi_uartlite_0;
	};
	aliases {
		ethernet0 = &axi_ethernetlite_0;
		serial0 = &axi_uartlite_0;
                i2c0 = &axi_iic_0;
                i2c1 = &axi_iic_1;
	};
	memory {
		device_type = "memory";
		reg = <0x80000000 0x8000000>;
	};
};
&axi_ethernetlite_0 {
	local-mac-address = [00 0a 35 00 00 00];
};

Generate your init RAM Disk for root File sytem. I suppose that you can do this.

Generate your Linux kernel. I suppose that you can do this:

$ make ARCH=microblaze CROSS_COMPILE=microblazeel-xilinx-linux-gnu- simpleImage.xilinx -j 4

 

Program the FPGA device and download the simpleImage.xilinx file (kernel + init RAM Disk) under arch/microblaze/boot directory  into RAM with the JTAG interface and finally execute.

That's all folks!

Ramdisk addr 0x00000000, 
Compiled-in FDT at c03ad4f8
Linux version 4.14.0-00493-gb68293ad2c93-dirty (kadionik@ipcchip) (gcc version 8
setup_cpuinfo: initialising
setup_cpuinfo: Using full CPU PVR support
wt_msr_noirq
setup_memory: max_mapnr: 0x8000
setup_memory: min_low_pfn: 0x80000
setup_memory: max_low_pfn: 0x88000
setup_memory: max_pfn: 0x88000
Zone ranges:
  DMA      [mem 0x0000000080000000-0x0000000087ffffff]
  Normal   empty
Movable zone start for each node
Early memory node ranges                                                        
  node   0: [mem 0x0000000080000000-0x0000000087ffffff]                         
Initmem setup node 0 [mem 0x0000000080000000-0x0000000087ffffff]                
On node 0 totalpages: 32768                                                     
free_area_init_node: node 0, pgdat c0525af4, node_mem_map c07a2000              
  DMA zone: 256 pages used for memmap                                           
  DMA zone: 0 pages reserved                                                    
  DMA zone: 32768 pages, LIFO batch:7                                           
pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768                                   
pcpu-alloc: [0] 0                                                               
Built 1 zonelists, mobility grouping on.  Total pages: 32512                    
Kernel command line: console=ttyUL0,9600                                        
PID hash table entries: 512 (order: -1, 2048 bytes)                             
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)                  
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)                    
Memory: 121948K/131072K available (3765K kernel code, 121K rwdata, 1312K rodata)
Kernel virtual memory layout:                                                   
  * 0xffffe000..0xfffff000  : fixmap                                            
  * 0xffffe000..0xffffe000  : early ioremap                                     
  * 0xf0000000..0xffffe000  : vmalloc & ioremap                                 
NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0                                  
irq-xilinx: /amba_pl/interrupt-controller@41200000: num_irq=5, edge=0x6         
/amba_pl/timer@41c00000: irq=1                                                  
clocksource: xilinx_clocksource: mask: 0xffffffff max_cycles: 0xffffffff, max_is
xilinx_timer_shutdown                                                           
xilinx_timer_set_periodic                                                       
sched_clock: 32 bits at 100MHz, resolution 10ns, wraps every 21474836475ns      
Calibrating delay loop... 49.15 BogoMIPS (lpj=245760)                           
pid_max: default: 4096 minimum: 301                                             
Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)                     
Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)                
random: get_random_u32 called from bucket_table_alloc+0x2e4/0x35c with crng_ini0
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 191s
NET: Registered protocol family 16                                              
clocksource: Switched to clocksource xilinx_clocksource                         
NET: Registered protocol family 2                                               
TCP established hash table entries: 1024 (order: 0, 4096 bytes)                 
TCP bind hash table entries: 1024 (order: 2, 20480 bytes)                       
TCP: Hash tables configured (established 1024 bind 1024)                        
UDP hash table entries: 128 (order: 0, 6144 bytes)                              
UDP-Lite hash table entries: 128 (order: 0, 6144 bytes)                         
NET: Registered protocol family 1                                               
RPC: Registered named UNIX socket transport module.                             
RPC: Registered udp transport module.                                           
RPC: Registered tcp transport module.                                           
RPC: Registered tcp NFSv4.1 backchannel transport module.                       
random: fast init done                                                          
Skipping unavailable RESET gpio -2 (reset)                                      
workingset: timestamp_bits=30 max_order=15 bucket_order=0                       
io scheduler noop registered                                                    
io scheduler deadline registered                                                
io scheduler cfq registered (default)                                           
io scheduler mq-deadline registered                                             
io scheduler kyber registered                                                   
Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled                        
40600000.serial: ttyUL0 at MMIO 0x40600000 (irq = 5, base_baud = 0) is a uartlie
console [ttyUL0] enabled                                                        
brd: module loaded                                                              
libphy: Fixed MDIO Bus: probed                                                  
xilinx_emaclite 40e00000.ethernet: Device Tree Probing                          
xilinx_emaclite 40e00000.ethernet: Failed to register mdio bus.                 
xilinx_emaclite 40e00000.ethernet: MAC address is now 00:0a:35:00:00:00         
xilinx_emaclite 40e00000.ethernet: Xilinx EmacLite at 0x40E00000 mapped to 0xF02
i2c /dev entries driver                                                         
NET: Registered protocol family 17                                              
Freeing unused kernel memory: 2296K                                             
This architecture does not have kernel memory protection.                       
    Hostname       : nexys4ddr                                                  
    Kernel release : Linux 4.14.0-00493-gb68293ad2c93-dirty                     
    Kernel version : #120 Thu Dec 6 16:51:57 CET 2018                           
                                                                                
                                                                                
Please press Enter to activate this console.                                    
nexys4ddr:/#

 

For the first I2C sensor (onboard ADT7420 sensor of the Nexys4 DDR board), we must use the /dev/i2c/0 (or /dev/i2c/i2c-0) character driver file (Major=89 minor=0).

For the second I2C sensor (external TCN75A PMOD TMP3 sensor), we must use the /dev/i2c/1 (or /dev/i2c/i2c-1) character driver file (Major=89 minor=1).

 

nexys4ddr:/# i2cdetect -y 0                                                     
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f                             
00:          -- -- -- -- -- -- -- -- -- -- -- -- --                             
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
40: -- -- -- -- -- -- -- -- -- -- -- 4b -- -- -- --                             
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
70: -- -- -- -- -- -- -- --                                                     
nexys4ddr:/# i2cdetect -y 1                                                     
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f                             
00:          -- -- -- -- -- -- -- -- -- -- -- -- --                             
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --                             
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
70: -- -- -- -- -- -- -- --  

You can now use the Linux API for reading the I2C sensors...

Pat.

 

 

 

 

 

Sans titre.png

Edited by kadionik

Share this post


Link to post
Share on other sites

1 answer to this question

Recommended Posts

  • 0

Please find enclosed source files for reading the onboard I2C temperature sensor (ADT7420) of the Nexys4 DDR board under Linux.

 

For cross compiling:

make CC=microblazeel-xilinx-linux-gnu-gcc -f Makefile

 

I'm using the gcc cross compiler from Vivado 2016.3 SDK.

Pat.

Makefile

libi2c.c

libi2c.h

main.c

Edited by kadionik

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this