Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12610 Discussions

I2C Master + BOA webserver (µClinux)

Altera_Forum
Honored Contributor II
1,478 Views

Hi guys, 

 

After the successful implementation a Boa embedded webserver using µClinux on the baseboard DBM_3C40, my idea is to use an I2C bus (interfaced through CGI/HTML page on the BOA server) in order to control/observe registers of some external peripherals.  

So I decided to choose the "OpenCores I2C (Longshot)" in my design. I have some questions concerning this module : 

 

1) In SOPCBuilder and Quartus, I simply connect the OpenCores I2C as following : 

 

http://img34.imageshack.us/img34/5669/sopci2c.jpg (http://img34.imageshack.us/img34/5669/sopci2c.jpg

http://img5.imageshack.us/img5/8771/quartusi2c.jpg (http://img5.imageshack.us/img5/8771/quartusi2c.jpg

 

+ Do I must connect the I2C component to a tristate-bridge or can I simply connect it to the "instruction_master" and "data_master" of the cpu (like the first screenshot) ?? 

+ There are warnings in SOPC console : "Signal chipselect appears 2 times (once only is allowed)" but I can't configure the I2C component...are they important warnings ?? 

 

2) To send some commands to the I2C peripherals through a CGI script (linked to a HTML page), I think about using the following C functions included in the file "opencores_i2c.h" : 

 

//int I2C_init(alt_u32 base,alt_u32 clk, alt_u32 speed) 

//int I2C_start(alt_u32 base, alt_u32 add, alt_u32 write); 

//alt_u32 I2C_read(alt_u32 base); 

//int I2C_write(alt_u32 base, alt_u8 data); 

 

But in the source code "opencores_i2c.c" , I found Altera functions like "IOWR_OPENCORES_I2C_CTR(...)", which are not included with the µClinux system... 

 

are there any equivalents of iowr(..) and iord(..) in the uclinux environment?  

 

Thanks for your help. 

Regards, 

 

Papy
0 Kudos
7 Replies
Altera_Forum
Honored Contributor II
530 Views

IOWR ,IORD 

 

the equivalent are outb, inb and alike 

the makros are defined in uClinux-dist\linux-2.6.x\include\asm-nios2nommu\io.h
0 Kudos
Altera_Forum
Honored Contributor II
530 Views

<div class='quotetop'>QUOTE (nacide @ Jul 10 2009, 02:00 AM) <{post_snapback}> (index.php?act=findpost&pid=23058)</div> 

--- Quote Start ---  

IOWR ,IORD 

 

the equivalent are outb, inb and alike 

the makros are defined in uClinux-dist\linux-2.6.x\include\asm-nios2nommu\io.h[/b] 

--- Quote End ---  

 

 

Thanks for your reply but I finally used the equivalent defined on the section "IO programming in user space" of the NIOS Wiki : 

# define IORD(address,offset) (*(volatile unsigned *)(((address)|0x80000000)+4*(offset)))# define IOWR(address,offset,value) (*(volatile unsigned *)(((address)|0x80000000)+4*(offset)))=(value) 

 

in order to have uncached defines for the Nios II Full version with Data Cache (-f). 

 

However, when I scope on the SDA/SCL lines, I can successfully see the I2C sequences send by the master but it seems that the interrupts for the ACK bit and for the data read from registers (send by the slave) don&#39;t work at all... 

 

Is there a link between the use of IORD/IOWR definitions (always uncached) and the fact that I cannot use interrupts ? 

 

Thanks ! 

 

Papy 

 

0 Kudos
Altera_Forum
Honored Contributor II
530 Views

IMHO it&#39;s not really good idea to work around the ways of the OS. While this will of course work with the current NIOSnommu system, I suppose it will not work with the upcoming MMU-enabled NIOS Linux. Moreover it&#39;s not portable at all regarding yet unknown Linux updates and other processors. The "correct" way of doing this is either create a decent device driver and to access I/O use the portable functions provided by the Kernel build system or - if you want to stay in userland - use UIO. In userland Interrupts are not possible. Of course the "official" way to use interrupts is doing a decent device driver. But I was told that UIO provides means to do a kind of "user-land-interrups" (I did not look into this yet). 

 

(I just updated the wiki page http://www.nioswiki.com/operatingsystems/u...ux/compilehello (http://www.nioswiki.com/operatingsystems/uclinux/compilehello) ) 

 

-Michael
0 Kudos
Altera_Forum
Honored Contributor II
530 Views

<div class='quotetop'>QUOTE (mschnell @ Jul 10 2009, 04:08 AM) <{post_snapback}> (index.php?act=findpost&pid=23060)</div> 

--- Quote Start ---  

IMHO it&#39;s not really good idea to work around the ways of the OS. While this will of course work with the current NIOSnommu system, I suppose it will not work with the upcoming MMU-enabled NIOS Linux. Moreover it&#39;s not portable at all regarding yet unknown Linux updates and other processors. The "correct" way of doing this is either create a decent device driver and to access I/O use the portable functions provided by the Kernel build system or - if you want to stay in userland - use UIO. In userland Interrupts are not possible. Of course the "official" way to use interrupts is doing a decent device driver. But I was told that UIO provides means to do a kind of "user-land-interrups" (I did not look into this yet). 

 

-Michael[/b] 

--- Quote End ---  

 

 

Does it mean that I can&#39;t use at all the HAL functions included in the "OpenCores I2C Package" ??? 

 

Because with this HAL, I can send I2C frames on the SDA/SCL lines very easily (I scoped yesterday and is was almost perfect), the only problem concerns the data received from the slave by the master like ACK bit or read registers... 

 

Is it possible in the same time to switch to NIOS Standard version (-s) in SOPC Builder (compatible with µClinux ??), to keep the OpenCores Ethernet MAC and the OpenCores I2C working and finally to use HAL functions like this one : 

 

 

------------------------------------------------------------------------------------ 

alt_u32 I2C_read(alt_u32 base,alt_u32 last) 

{# ifdef I2C_DEBUG 

printf(" Read I2C at 0x%x, \n\twith last0x%x\n",base,last);# endif 

if( last) 

/* start a read and no ack and stop bit*/ 

IOWR_OPENCORES_I2C_CR(base, OPENCORES_I2C_CR_RD_MSK | 

OPENCORES_I2C_CR_NACK_MSK | OPENCORES_I2C_CR_STO_MSK); 

else 

/* start read*/ 

IOWR_OPENCORES_I2C_CR(base, OPENCORES_I2C_CR_RD_MSK ); 

/* wait for the trnasaction to be over.*/ 

while( IORD_OPENCORES_I2C_SR(base) & OPENCORES_I2C_SR_TIP_MSK); 

 

/* now read the data */ 

return (IORD_OPENCORES_I2C_RXR(base)); 

------------------------------------------------------------------------------------ 

 

 

Thanks for your help !
0 Kudos
Altera_Forum
Honored Contributor II
530 Views

There already is a device driver for the OpenCores I²C Controller. 

 

in my Kernel configuration I see this: (I set the [*] where I suppose you need them.) 

Device Drivers  --->     <*> I2C device interface     <*> I2C support  --->     I2C Hardware Bus support  --->      *** I2C system bus drivers (mostly embedded / system-on-chip) ***   <*> OpenCores I2C Controller < > Simtec Generic I2C interface (NEW)            *** External I2C/SMBus adapter drivers ***     < > Parallel port adapter (light) (NEW)       < > TAOS evaluation module (NEW)                       *** Other I2C/SMBus bus drivers ***                 < > PCA9564/PCA9665 as platform device (NEW)     < > I2C/SMBus Test Stub (NEW) 

So you don&#39;t need to use hardware registers or interrupts in your own code. You just need to create an appropriate driver for the I²C chip you want to use. For communication with the chip, this driver uses the "open Cores" I²C hardware via the I²C subsystem. Seehttp://www.nioswiki.com/OperatingSystems/UClinux/Video for more info. 

 

There seem to be six chip drivers provided that use this bus. you might take a look at their source code to find out how to access the I²C subsystem. 

 

-Michael
0 Kudos
Altera_Forum
Honored Contributor II
530 Views

<div class='quotetop'>QUOTE (mschnell @ Jul 10 2009, 05:56 AM) <{post_snapback}> (index.php?act=findpost&pid=23062)</div> 

--- Quote Start ---  

You just need to create an appropriate driver for the I²C chip you want to use.[/b] 

--- Quote End ---  

 

 

I already selected "I2C Device Interface" and "OpenCores I2C Controller" in my Kernel configuration and as mentionned previously, I can send I2C frames from the master part (NIOS II) to the selected slave (a temperature sensor) but I don&#39;t receive ACK or data from the I2C slave on the screen, whereas on the scope, I can see the ACK bit low (=defined)... Here is the simple code used, based on the HAL functions : 

 

--------------------------------------------------------------------------- 

/* these test were created to show how to use the opencores i2c along with a driver found in 

* the opencores_I2C component to talk to various components.  

* This test example uses a littel daughter board from microtronix 

* it has a I2c to parallel chip (PCA9554A) a EEPORM and real time clock. */ 

 

I2C_init(na_i2c,na_i2c_clock_freq,100000); 

 

I2C_start(na_i2c,0x4a,0); //set chip address in write mode 

I2C_write(na_i2c,0,0); // write the first index of the register that must be read 

 

I2C_start(na_i2c,0x4a,1); //set chip address in read mode 

 

data = I2C_read(na_i2c,0); // read continues after this burst 

printf("\tdata = 0x%x\n",data); 

 

data = I2C_read(na_i2c,1); // last read 

printf("\tdata = 0x%x\n",data); 

--------------------------------------------------------------------------- 

 

If I understand well, every time I add an I2C slave on the bus controlled by the master, I must write a I2C chip driver in the folder <nios2-linux/linux-2.6/drivers/i2c/chips> and recompile ??? 

The interrupt problem cannot be resolved with an easier solution regarding my system ?? I only need to retrieve data... 

 

Thanks for your help, I&#39;m a little confused between I2C core, I2C bus drivers, I2C algorithm drivers and I2C chip drivers :(
0 Kudos
Altera_Forum
Honored Contributor II
530 Views

If using the Linux Kernel I²C subsystem, you don&#39;t need to bother with the HAL or any hardware addresses, at all.  

 

This: 

>>IOWR_OPENCORES_I2C_CR(base, OPENCORES_I2C_CR_RD_MSK | 

>>OPENCORES_I2C_CR_NACK_MSK | OPENCORES_I2C_CR_STO_MSK); 

Seems to be direct hardware acces and not using the I²C subsystem and the Kernel driver for the OpenCores interface (be it enabled otr not). 

 

Unfortunately I did not yet use the I²C subsystem, so I can&#39;t help with it&#39;s interface, but I think it can used only by Kernel drivers. 

 

I suppose that the ACK receiving is done by the line driver and not in the responsibility of the chip driver. 

 

How do you know that you don&#39;t receive an ACK ? This might be some interrupt issue. If using a Kernel driver for the interface hardware&#39;, you are not allowed to access these hardware registers by any other software.  

 

Do you know that the bits are set to the chip ?  

 

>>>If I understand well, every time I add an I2C slave on the bus controlled by the master, I must write a I2C chip driver in the folder <nios2-linux/linux-2.6/drivers/i2c/chips> and recompile ??? 

 

I suppose this is true. 

 

>>>The interrupt problem cannot be resolved with an easier solution regarding my system ?? I only need to retrieve data... 

 

I suppose the OpenCores I²C interface "hardware" and the appropriate driver (that you already seem to have successfully compiled) do handle th interrupt for you. Using the I²C subsystem should be easier and more portable than to do everything from scratch in whatever way. So what are you trying to accomplish ?  

 

Happy hunting and let us know what you find ! 

-Michael
0 Kudos
Reply